aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt11
-rw-r--r--al/auxeffectslot.cpp152
-rw-r--r--al/auxeffectslot.h39
-rw-r--r--al/buffer.cpp59
-rw-r--r--al/buffer.h21
-rw-r--r--al/debug.cpp2
-rw-r--r--al/direct_defs.h28
-rw-r--r--al/eax/api.h11
-rw-r--r--al/eax/call.cpp3
-rw-r--r--al/eax/call.h28
-rw-r--r--al/eax/effect.h243
-rw-r--r--al/eax/fx_slots.h9
-rw-r--r--al/eax/globals.h2
-rw-r--r--al/effect.cpp288
-rw-r--r--al/effect.h34
-rw-r--r--al/effects/autowah.cpp119
-rw-r--r--al/effects/chorus.cpp269
-rw-r--r--al/effects/compressor.cpp65
-rw-r--r--al/effects/convolution.cpp82
-rw-r--r--al/effects/dedicated.cpp92
-rw-r--r--al/effects/distortion.cpp117
-rw-r--r--al/effects/echo.cpp117
-rw-r--r--al/effects/effects.h88
-rw-r--r--al/effects/equalizer.cpp172
-rw-r--r--al/effects/fshifter.cpp113
-rw-r--r--al/effects/modulator.cpp129
-rw-r--r--al/effects/null.cpp63
-rw-r--r--al/effects/pshifter.cpp89
-rw-r--r--al/effects/reverb.cpp834
-rw-r--r--al/effects/vmorpher.cpp208
-rw-r--r--al/error.cpp54
-rw-r--r--al/event.cpp2
-rw-r--r--al/filter.cpp58
-rw-r--r--al/filter.h28
-rw-r--r--al/listener.h2
-rw-r--r--al/source.cpp289
-rw-r--r--al/source.h69
-rw-r--r--al/state.cpp28
-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
-rw-r--r--alsoftrc.sample2
-rw-r--r--common/albit.h7
-rw-r--r--common/alcomplex.cpp2
-rw-r--r--common/almalloc.cpp61
-rw-r--r--common/almalloc.h208
-rw-r--r--common/alnumbers.h8
-rw-r--r--common/alnumeric.h2
-rw-r--r--common/alsem.h2
-rw-r--r--common/alspan.h198
-rw-r--r--common/althrd_setname.cpp2
-rw-r--r--common/atomic.h86
-rw-r--r--common/dynload.cpp7
-rw-r--r--common/flexarray.h125
-rw-r--r--common/intrusive_ptr.h8
-rw-r--r--common/opthelpers.h2
-rw-r--r--common/pffft.cpp178
-rw-r--r--common/pffft.h78
-rw-r--r--common/phase_shifter.h10
-rw-r--r--common/polyphase_resampler.h2
-rw-r--r--common/ringbuffer.cpp20
-rw-r--r--common/ringbuffer.h27
-rw-r--r--common/vecmat.h8
-rw-r--r--config.h.in6
-rw-r--r--core/ambdec.cpp37
-rw-r--r--core/ambdec.h10
-rw-r--r--core/async_event.h3
-rw-r--r--core/bformatdec.cpp16
-rw-r--r--core/bformatdec.h10
-rw-r--r--core/bs2b.cpp127
-rw-r--r--core/bs2b.h81
-rw-r--r--core/bsinc_tables.cpp19
-rw-r--r--core/bsinc_tables.h6
-rw-r--r--core/buffer_storage.cpp2
-rw-r--r--core/buffer_storage.h10
-rw-r--r--core/context.cpp144
-rw-r--r--core/context.h38
-rw-r--r--core/converter.cpp63
-rw-r--r--core/converter.h17
-rw-r--r--core/cubic_defs.h6
-rw-r--r--core/cubic_tables.cpp4
-rw-r--r--core/dbus_wrap.cpp20
-rw-r--r--core/devformat.h3
-rw-r--r--core/device.cpp11
-rw-r--r--core/device.h111
-rw-r--r--core/effects/base.h269
-rw-r--r--core/effectslot.cpp8
-rw-r--r--core/effectslot.h5
-rw-r--r--core/except.cpp2
-rw-r--r--core/except.h7
-rw-r--r--core/filters/biquad.cpp4
-rw-r--r--core/filters/biquad.h4
-rw-r--r--core/filters/nfc.cpp12
-rw-r--r--core/filters/nfc.h25
-rw-r--r--core/fmt_traits.cpp8
-rw-r--r--core/fmt_traits.h5
-rw-r--r--core/fpu_ctrl.cpp21
-rw-r--r--core/fpu_ctrl.h23
-rw-r--r--core/front_stablizer.h1
-rw-r--r--core/helpers.cpp4
-rw-r--r--core/helpers.h4
-rw-r--r--core/hrtf.cpp142
-rw-r--r--core/hrtf.h21
-rw-r--r--core/logging.h4
-rw-r--r--core/mastering.cpp237
-rw-r--r--core/mastering.h27
-rw-r--r--core/mixer/defs.h21
-rw-r--r--core/mixer/mixer_c.cpp68
-rw-r--r--core/mixer/mixer_neon.cpp41
-rw-r--r--core/mixer/mixer_sse.cpp28
-rw-r--r--core/mixer/mixer_sse2.cpp4
-rw-r--r--core/mixer/mixer_sse41.cpp4
-rw-r--r--core/rtkit.cpp4
-rw-r--r--core/uhjfilter.cpp37
-rw-r--r--core/uhjfilter.h12
-rw-r--r--core/voice.cpp98
-rw-r--r--core/voice.h65
-rw-r--r--core/voice_change.h4
-rw-r--r--examples/alconvolve.c37
-rw-r--r--examples/alffplay.cpp140
-rw-r--r--examples/alhrtf.c2
-rw-r--r--examples/allatency.c2
-rw-r--r--examples/almultireverb.c8
-rw-r--r--examples/alplay.c2
-rw-r--r--examples/alreverb.c2
-rw-r--r--examples/alstream.c41
-rw-r--r--examples/alstreamcb.cpp47
-rw-r--r--examples/altonegen.c1
-rw-r--r--include/AL/al.h2
-rw-r--r--include/AL/alc.h2
-rw-r--r--include/AL/alext.h2
-rw-r--r--include/AL/efx-presets.h2
-rw-r--r--include/AL/efx.h2
-rw-r--r--router/al.cpp19
-rw-r--r--router/alc.cpp13
-rw-r--r--router/router.cpp11
-rw-r--r--utils/alsoft-config/CMakeLists.txt2
-rw-r--r--utils/alsoft-config/mainwindow.cpp318
-rw-r--r--utils/alsoft-config/mainwindow.h29
-rw-r--r--utils/makemhr/loaddef.cpp574
-rw-r--r--utils/makemhr/loadsofa.cpp43
-rw-r--r--utils/makemhr/makemhr.cpp300
-rw-r--r--utils/makemhr/makemhr.h36
-rw-r--r--utils/openal-info.c25
-rw-r--r--utils/sofa-info.cpp3
-rw-r--r--utils/sofa-support.cpp8
-rw-r--r--utils/uhjdecoder.cpp36
-rw-r--r--utils/uhjencoder.cpp108
191 files changed, 6400 insertions, 6468 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 2d572908..2a3900ca 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -329,7 +329,7 @@ else()
option(ALSOFT_STATIC_STDCXX "Static link libstdc++" OFF)
if(ALSOFT_STATIC_STDCXX)
set(OLD_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES})
- set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} "-Wl,--push-state,-Bstatic,-lstdc++,--pop-state")
+ set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} "-static-libstdc++")
check_cxx_source_compiles("int main() { }" HAVE_STATIC_LIBSTDCXX_SWITCH)
set(CMAKE_REQUIRED_LIBRARIES ${OLD_REQUIRED_LIBRARIES})
unset(OLD_REQUIRED_LIBRARIES)
@@ -337,7 +337,7 @@ else()
if(NOT HAVE_STATIC_LIBSTDCXX_SWITCH)
message(FATAL_ERROR "Cannot static link libstdc++")
endif()
- set(LINKER_FLAGS ${LINKER_FLAGS} "-Wl,--push-state,-Bstatic,-lstdc++,--pop-state")
+ set(LINKER_FLAGS ${LINKER_FLAGS} "-static-libstdc++")
endif()
if(WIN32)
@@ -565,8 +565,6 @@ if(HAVE_INTRIN_H)
}" HAVE_CPUID_INTRINSIC)
endif()
-check_symbol_exists(posix_memalign stdlib.h HAVE_POSIX_MEMALIGN)
-check_symbol_exists(_aligned_malloc malloc.h HAVE__ALIGNED_MALLOC)
check_symbol_exists(proc_pidpath libproc.h HAVE_PROC_PIDPATH)
if(NOT WIN32)
@@ -622,7 +620,6 @@ set(COMMON_OBJS
common/alcomplex.h
common/alfstream.cpp
common/alfstream.h
- common/almalloc.cpp
common/almalloc.h
common/alnumbers.h
common/alnumeric.h
@@ -638,6 +635,7 @@ set(COMMON_OBJS
common/comptr.h
common/dynload.cpp
common/dynload.h
+ common/flexarray.h
common/intrusive_ptr.h
common/opthelpers.h
common/pffft.cpp
@@ -1351,7 +1349,8 @@ configure_file(
add_library(alcommon STATIC EXCLUDE_FROM_ALL ${COMMON_OBJS})
-target_include_directories(alcommon PRIVATE ${OpenAL_BINARY_DIR} ${OpenAL_SOURCE_DIR}/include)
+target_include_directories(alcommon PRIVATE ${OpenAL_BINARY_DIR} ${OpenAL_SOURCE_DIR}/include
+ PUBLIC ${OpenAL_SOURCE_DIR}/common)
target_compile_definitions(alcommon PRIVATE ${CPP_DEFS})
target_compile_options(alcommon PRIVATE ${C_FLAGS})
set_target_properties(alcommon PROPERTIES ${DEFAULT_TARGET_PROPS} POSITION_INDEPENDENT_CODE TRUE)
diff --git a/al/auxeffectslot.cpp b/al/auxeffectslot.cpp
index fb646389..673ca4c9 100644
--- a/al/auxeffectslot.cpp
+++ b/al/auxeffectslot.cpp
@@ -53,33 +53,35 @@
namespace {
+using SubListAllocator = typename al::allocator<std::array<ALeffectslot,64>>;
+
struct FactoryItem {
EffectSlotType Type;
- EffectStateFactory* (&GetFactory)(void);
+ EffectStateFactory* (&GetFactory)();
};
-constexpr FactoryItem FactoryList[] = {
- { EffectSlotType::None, NullStateFactory_getFactory },
- { EffectSlotType::EAXReverb, ReverbStateFactory_getFactory },
- { EffectSlotType::Reverb, StdReverbStateFactory_getFactory },
- { EffectSlotType::Autowah, AutowahStateFactory_getFactory },
- { EffectSlotType::Chorus, ChorusStateFactory_getFactory },
- { EffectSlotType::Compressor, CompressorStateFactory_getFactory },
- { EffectSlotType::Distortion, DistortionStateFactory_getFactory },
- { EffectSlotType::Echo, EchoStateFactory_getFactory },
- { EffectSlotType::Equalizer, EqualizerStateFactory_getFactory },
- { EffectSlotType::Flanger, FlangerStateFactory_getFactory },
- { EffectSlotType::FrequencyShifter, FshifterStateFactory_getFactory },
- { EffectSlotType::RingModulator, ModulatorStateFactory_getFactory },
- { EffectSlotType::PitchShifter, PshifterStateFactory_getFactory },
- { EffectSlotType::VocalMorpher, VmorpherStateFactory_getFactory },
- { EffectSlotType::DedicatedDialog, DedicatedStateFactory_getFactory },
- { EffectSlotType::DedicatedLFE, DedicatedStateFactory_getFactory },
- { EffectSlotType::Convolution, ConvolutionStateFactory_getFactory },
+constexpr std::array FactoryList{
+ FactoryItem{EffectSlotType::None, NullStateFactory_getFactory},
+ FactoryItem{EffectSlotType::EAXReverb, ReverbStateFactory_getFactory},
+ FactoryItem{EffectSlotType::Reverb, StdReverbStateFactory_getFactory},
+ FactoryItem{EffectSlotType::Autowah, AutowahStateFactory_getFactory},
+ FactoryItem{EffectSlotType::Chorus, ChorusStateFactory_getFactory},
+ FactoryItem{EffectSlotType::Compressor, CompressorStateFactory_getFactory},
+ FactoryItem{EffectSlotType::Distortion, DistortionStateFactory_getFactory},
+ FactoryItem{EffectSlotType::Echo, EchoStateFactory_getFactory},
+ FactoryItem{EffectSlotType::Equalizer, EqualizerStateFactory_getFactory},
+ FactoryItem{EffectSlotType::Flanger, FlangerStateFactory_getFactory},
+ FactoryItem{EffectSlotType::FrequencyShifter, FshifterStateFactory_getFactory},
+ FactoryItem{EffectSlotType::RingModulator, ModulatorStateFactory_getFactory},
+ FactoryItem{EffectSlotType::PitchShifter, PshifterStateFactory_getFactory},
+ FactoryItem{EffectSlotType::VocalMorpher, VmorpherStateFactory_getFactory},
+ FactoryItem{EffectSlotType::DedicatedDialog, DedicatedDialogStateFactory_getFactory},
+ FactoryItem{EffectSlotType::DedicatedLFE, DedicatedLfeStateFactory_getFactory},
+ FactoryItem{EffectSlotType::Convolution, ConvolutionStateFactory_getFactory},
};
EffectStateFactory *getFactoryByType(EffectSlotType type)
{
- auto iter = std::find_if(std::begin(FactoryList), std::end(FactoryList),
+ auto iter = std::find_if(FactoryList.begin(), FactoryList.end(),
[type](const FactoryItem &item) noexcept -> bool
{ return item.Type == type; });
return (iter != std::end(FactoryList)) ? iter->GetFactory() : nullptr;
@@ -96,7 +98,7 @@ inline ALeffectslot *LookupEffectSlot(ALCcontext *context, ALuint id) noexcept
EffectSlotSubList &sublist{context->mEffectSlotList[lidx]};
if(sublist.FreeMask & (1_u64 << slidx)) UNLIKELY
return nullptr;
- return sublist.EffectSlots + slidx;
+ return al::to_address(sublist.EffectSlots->begin() + slidx);
}
inline ALeffect *LookupEffect(ALCdevice *device, ALuint id) noexcept
@@ -109,7 +111,7 @@ inline ALeffect *LookupEffect(ALCdevice *device, ALuint id) noexcept
EffectSubList &sublist = device->EffectList[lidx];
if(sublist.FreeMask & (1_u64 << slidx)) UNLIKELY
return nullptr;
- return sublist.Effects + slidx;
+ return al::to_address(sublist.Effects->begin() + slidx);
}
inline ALbuffer *LookupBuffer(ALCdevice *device, ALuint id) noexcept
@@ -122,7 +124,7 @@ inline ALbuffer *LookupBuffer(ALCdevice *device, ALuint id) noexcept
BufferSubList &sublist = device->BufferList[lidx];
if(sublist.FreeMask & (1_u64 << slidx)) UNLIKELY
return nullptr;
- return sublist.Buffers + slidx;
+ return al::to_address(sublist.Buffers->begin() + slidx);
}
@@ -155,19 +157,17 @@ void AddActiveEffectSlots(const al::span<ALeffectslot*> auxslots, ALCcontext *co
*/
if(newcount < newarray->size()) UNLIKELY
{
- curarray = newarray;
+ std::unique_ptr<EffectSlotArray> oldarray{newarray};
newarray = EffectSlot::CreatePtrArray(newcount);
- std::copy_n(curarray->begin(), newcount, newarray->begin());
- delete curarray;
- curarray = nullptr;
+ std::copy_n(oldarray->begin(), newcount, newarray->begin());
}
std::uninitialized_fill_n(newarray->end(), newcount, nullptr);
- curarray = context->mActiveAuxSlots.exchange(newarray, std::memory_order_acq_rel);
- context->mDevice->waitForMix();
+ std::unique_ptr<EffectSlotArray> oldarray{context->mActiveAuxSlots.exchange(newarray,
+ std::memory_order_acq_rel)};
+ std::ignore = context->mDevice->waitForMix();
- std::destroy_n(curarray->end(), curarray->size());
- delete curarray;
+ std::destroy_n(oldarray->end(), oldarray->size());
}
void RemoveActiveEffectSlots(const al::span<ALeffectslot*> auxslots, ALCcontext *context)
@@ -193,20 +193,17 @@ void RemoveActiveEffectSlots(const al::span<ALeffectslot*> auxslots, ALCcontext
auto newsize = static_cast<size_t>(std::distance(newarray->begin(), new_end));
if(newsize != newarray->size()) LIKELY
{
- curarray = newarray;
+ std::unique_ptr<EffectSlotArray> oldarray{newarray};
newarray = EffectSlot::CreatePtrArray(newsize);
- std::copy_n(curarray->begin(), newsize, newarray->begin());
-
- delete curarray;
- curarray = nullptr;
+ std::copy_n(oldarray->begin(), newsize, newarray->begin());
}
std::uninitialized_fill_n(newarray->end(), newsize, nullptr);
- curarray = context->mActiveAuxSlots.exchange(newarray, std::memory_order_acq_rel);
- context->mDevice->waitForMix();
+ std::unique_ptr<EffectSlotArray> oldarray{context->mActiveAuxSlots.exchange(newarray,
+ std::memory_order_acq_rel)};
+ std::ignore = context->mDevice->waitForMix();
std::destroy_n(curarray->end(), curarray->size());
- delete curarray;
}
@@ -243,22 +240,21 @@ bool EnsureEffectSlots(ALCcontext *context, size_t needed)
[](size_t cur, const EffectSlotSubList &sublist) noexcept -> size_t
{ return cur + static_cast<ALuint>(al::popcount(sublist.FreeMask)); })};
- while(needed > count)
- {
- if(context->mEffectSlotList.size() >= 1<<25) UNLIKELY
- return false;
-
- context->mEffectSlotList.emplace_back();
- auto sublist = context->mEffectSlotList.end() - 1;
- sublist->FreeMask = ~0_u64;
- sublist->EffectSlots = static_cast<ALeffectslot*>(
- al_calloc(alignof(ALeffectslot), sizeof(ALeffectslot)*64));
- if(!sublist->EffectSlots) UNLIKELY
+ try {
+ while(needed > count)
{
- context->mEffectSlotList.pop_back();
- return false;
+ if(context->mEffectSlotList.size() >= 1<<25) UNLIKELY
+ return false;
+
+ EffectSlotSubList sublist{};
+ sublist.FreeMask = ~0_u64;
+ sublist.EffectSlots = SubListAllocator{}.allocate(1);
+ context->mEffectSlotList.emplace_back(std::move(sublist));
+ count += 64;
}
- count += 64;
+ }
+ catch(...) {
+ return false;
}
return true;
}
@@ -272,7 +268,8 @@ ALeffectslot *AllocEffectSlot(ALCcontext *context)
auto slidx = static_cast<ALuint>(al::countr_zero(sublist->FreeMask));
ASSUME(slidx < 64);
- ALeffectslot *slot{al::construct_at(sublist->EffectSlots + slidx, context)};
+ ALeffectslot *slot{al::construct_at(al::to_address(sublist->EffectSlots->begin() + slidx),
+ context)};
aluInitEffectPanning(slot->mSlot, context);
/* Add 1 to avoid ID 0. */
@@ -370,7 +367,7 @@ FORCE_ALIGN void AL_APIENTRY alDeleteAuxiliaryEffectSlotsDirect(ALCcontext *cont
context->setError(AL_INVALID_NAME, "Invalid effect slot ID %u", effectslots[0]);
return;
}
- if(ReadRef(slot->ref) != 0) UNLIKELY
+ if(slot->ref.load(std::memory_order_relaxed) != 0) UNLIKELY
{
context->setError(AL_INVALID_OPERATION, "Deleting in-use effect slot %u",
effectslots[0]);
@@ -390,7 +387,7 @@ FORCE_ALIGN void AL_APIENTRY alDeleteAuxiliaryEffectSlotsDirect(ALCcontext *cont
context->setError(AL_INVALID_NAME, "Invalid effect slot ID %u", effectslots[i]);
return;
}
- if(ReadRef(slot->ref) != 0) UNLIKELY
+ if(slot->ref.load(std::memory_order_relaxed) != 0) UNLIKELY
{
context->setError(AL_INVALID_OPERATION, "Deleting in-use effect slot %u",
effectslots[i]);
@@ -880,12 +877,8 @@ ALeffectslot::~ALeffectslot()
DecrementRef(Buffer->ref);
Buffer = nullptr;
- if(EffectSlotProps *props{mSlot->Update.exchange(nullptr)})
- {
- TRACE("Freed unapplied AuxiliaryEffectSlot update %p\n",
- decltype(std::declval<void*>()){props});
- delete props;
- }
+ if(auto *slot = mSlot->Update.exchange(nullptr, std::memory_order_relaxed))
+ slot->State = nullptr;
mSlot->mEffectState = nullptr;
mSlot->InUse = false;
@@ -923,7 +916,7 @@ ALenum ALeffectslot::initEffect(ALuint effectId, ALenum effectType, const Effect
EffectId = effectId;
/* Remove state references from old effect slot property updates. */
- EffectSlotProps *props{context->mFreeEffectslotProps.load()};
+ EffectSlotProps *props{context->mFreeEffectSlotProps.load()};
while(props)
{
props->State = nullptr;
@@ -936,17 +929,17 @@ ALenum ALeffectslot::initEffect(ALuint effectId, ALenum effectType, const Effect
void ALeffectslot::updateProps(ALCcontext *context)
{
/* Get an unused property container, or allocate a new one as needed. */
- EffectSlotProps *props{context->mFreeEffectslotProps.load(std::memory_order_relaxed)};
+ EffectSlotProps *props{context->mFreeEffectSlotProps.load(std::memory_order_acquire)};
if(!props)
- props = new EffectSlotProps{};
- else
{
- EffectSlotProps *next;
- do {
- next = props->next.load(std::memory_order_relaxed);
- } while(context->mFreeEffectslotProps.compare_exchange_weak(props, next,
- std::memory_order_seq_cst, std::memory_order_acquire) == 0);
+ context->allocEffectSlotProps();
+ props = context->mFreeEffectSlotProps.load(std::memory_order_acquire);
}
+ EffectSlotProps *next;
+ do {
+ next = props->next.load(std::memory_order_relaxed);
+ } while(context->mFreeEffectSlotProps.compare_exchange_weak(props, next,
+ std::memory_order_acq_rel, std::memory_order_acquire) == false);
/* Copy in current property values. */
props->Gain = Gain;
@@ -965,7 +958,7 @@ void ALeffectslot::updateProps(ALCcontext *context)
* freelist.
*/
props->State = nullptr;
- AtomicReplaceHead(context->mFreeEffectslotProps, props);
+ AtomicReplaceHead(context->mFreeEffectSlotProps, props);
}
}
@@ -988,12 +981,12 @@ void UpdateAllEffectSlotProps(ALCcontext *context)
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);
- ALeffectslot *slot{sublist.EffectSlots + idx};
+ auto &slot = (*sublist.EffectSlots)[idx];
- if(slot->mState != SlotState::Stopped && std::exchange(slot->mPropsDirty, false))
- slot->updateProps(context);
+ if(slot.mState != SlotState::Stopped && std::exchange(slot.mPropsDirty, false))
+ slot.updateProps(context);
}
}
}
@@ -1007,11 +1000,11 @@ EffectSlotSubList::~EffectSlotSubList()
while(usemask)
{
const int idx{al::countr_zero(usemask)};
- std::destroy_at(EffectSlots+idx);
+ std::destroy_at(al::to_address(EffectSlots->begin() + idx));
usemask &= ~(1_u64 << idx);
}
FreeMask = ~usemask;
- al_free(EffectSlots);
+ SubListAllocator{}.deallocate(EffectSlots, 1);
EffectSlots = nullptr;
}
@@ -1530,7 +1523,8 @@ void eax_delete_al_effect_slot(ALCcontext& context, ALeffectslot& effect_slot)
std::lock_guard<std::mutex> effect_slot_lock{context.mEffectSlotLock};
- if(ReadRef(effect_slot.ref) != 0) {
+ if(effect_slot.ref.load(std::memory_order_relaxed) != 0)
+ {
ERR(EAX_PREFIX "Deleting in-use effect slot %u.\n", effect_slot.id);
return;
}
diff --git a/al/auxeffectslot.h b/al/auxeffectslot.h
index 1ad0ffc4..6946591e 100644
--- a/al/auxeffectslot.h
+++ b/al/auxeffectslot.h
@@ -3,6 +3,7 @@
#include <atomic>
#include <cstddef>
+#include <cstdint>
#include <string_view>
#include "AL/al.h"
@@ -12,6 +13,7 @@
#include "alc/device.h"
#include "alc/effects/base.h"
#include "almalloc.h"
+#include "alnumeric.h"
#include "atomic.h"
#include "core/effectslot.h"
#include "intrusive_ptr.h"
@@ -63,7 +65,7 @@ struct ALeffectslot {
SlotState mState{SlotState::Initial};
- RefCount ref{0u};
+ std::atomic<ALuint> ref{0u};
EffectSlot *mSlot{nullptr};
@@ -81,20 +83,17 @@ struct ALeffectslot {
static void SetName(ALCcontext *context, ALuint id, std::string_view name);
- /* This can be new'd for the context's default effect slot. */
- DEF_NEWDEL(ALeffectslot)
-
#ifdef ALSOFT_EAX
public:
void eax_initialize(ALCcontext& al_context, EaxFxSlotIndexValue index);
- EaxFxSlotIndexValue eax_get_index() const noexcept { return eax_fx_slot_index_; }
- const EAX50FXSLOTPROPERTIES& eax_get_eax_fx_slot() const noexcept
+ [[nodiscard]] auto eax_get_index() const noexcept -> EaxFxSlotIndexValue { return eax_fx_slot_index_; }
+ [[nodiscard]] auto eax_get_eax_fx_slot() const noexcept -> const EAX50FXSLOTPROPERTIES&
{ return eax_; }
// Returns `true` if all sources should be updated, or `false` otherwise.
- bool eax_dispatch(const EaxCall& call)
+ [[nodiscard]] auto eax_dispatch(const EaxCall& call) -> bool
{ return call.is_get() ? eax_get(call) : eax_set(call); }
void eax_commit();
@@ -282,14 +281,14 @@ private:
dst = src;
}
- constexpr bool eax4_fx_slot_is_legacy() const noexcept
+ [[nodiscard]] constexpr auto eax4_fx_slot_is_legacy() const noexcept -> bool
{ return eax_fx_slot_index_ < 2; }
void eax4_fx_slot_ensure_unlocked() const;
- static ALenum eax_get_efx_effect_type(const GUID& guid);
- const GUID& eax_get_eax_default_effect_guid() const noexcept;
- long eax_get_eax_default_lock() const noexcept;
+ [[nodiscard]] static auto eax_get_efx_effect_type(const GUID& guid) -> ALenum;
+ [[nodiscard]] auto eax_get_eax_default_effect_guid() const noexcept -> const GUID&;
+ [[nodiscard]] auto eax_get_eax_default_lock() const noexcept -> long;
void eax4_fx_slot_set_defaults(Eax4Props& props) noexcept;
void eax5_fx_slot_set_defaults(Eax5Props& props) noexcept;
@@ -312,7 +311,7 @@ private:
void eax4_fx_slot_set_all(const EaxCall& call);
void eax5_fx_slot_set_all(const EaxCall& call);
- bool eax_fx_slot_should_update_sources() const noexcept;
+ [[nodiscard]] auto eax_fx_slot_should_update_sources() const noexcept -> bool;
// Returns `true` if all sources should be updated, or `false` otherwise.
bool eax4_fx_slot_set(const EaxCall& call);
@@ -370,4 +369,20 @@ EaxAlEffectSlotUPtr eax_create_al_effect_slot(ALCcontext& context);
void eax_delete_al_effect_slot(ALCcontext& context, ALeffectslot& effect_slot);
#endif // ALSOFT_EAX
+struct EffectSlotSubList {
+ uint64_t FreeMask{~0_u64};
+ gsl::owner<std::array<ALeffectslot,64>*> EffectSlots{nullptr};
+
+ 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; }
+};
+
#endif
diff --git a/al/buffer.cpp b/al/buffer.cpp
index 7d043036..b7ed5b32 100644
--- a/al/buffer.cpp
+++ b/al/buffer.cpp
@@ -68,6 +68,8 @@
namespace {
+using SubListAllocator = typename al::allocator<std::array<ALbuffer,64>>;
+
std::optional<AmbiLayout> AmbiLayoutFromEnum(ALenum layout)
{
switch(layout)
@@ -178,21 +180,21 @@ bool EnsureBuffers(ALCdevice *device, size_t needed)
[](size_t cur, const BufferSubList &sublist) noexcept -> size_t
{ return cur + static_cast<ALuint>(al::popcount(sublist.FreeMask)); })};
- while(needed > count)
- {
- if(device->BufferList.size() >= 1<<25) UNLIKELY
- return false;
-
- device->BufferList.emplace_back();
- auto sublist = device->BufferList.end() - 1;
- sublist->FreeMask = ~0_u64;
- sublist->Buffers = static_cast<ALbuffer*>(al_calloc(alignof(ALbuffer), sizeof(ALbuffer)*64));
- if(!sublist->Buffers) UNLIKELY
+ try {
+ while(needed > count)
{
- device->BufferList.pop_back();
- return false;
+ if(device->BufferList.size() >= 1<<25) UNLIKELY
+ return false;
+
+ BufferSubList sublist{};
+ sublist.FreeMask = ~0_u64;
+ sublist.Buffers = SubListAllocator{}.allocate(1);
+ device->BufferList.emplace_back(std::move(sublist));
+ count += 64;
}
- count += 64;
+ }
+ catch(...) {
+ return false;
}
return true;
}
@@ -206,7 +208,7 @@ ALbuffer *AllocBuffer(ALCdevice *device)
auto slidx = static_cast<ALuint>(al::countr_zero(sublist->FreeMask));
ASSUME(slidx < 64);
- ALbuffer *buffer{al::construct_at(sublist->Buffers + slidx)};
+ ALbuffer *buffer{al::construct_at(al::to_address(sublist->Buffers->begin() + slidx))};
/* Add 1 to avoid buffer ID 0. */
buffer->id = ((lidx<<6) | slidx) + 1;
@@ -243,7 +245,7 @@ inline ALbuffer *LookupBuffer(ALCdevice *device, ALuint id)
BufferSubList &sublist = device->BufferList[lidx];
if(sublist.FreeMask & (1_u64 << slidx)) UNLIKELY
return nullptr;
- return sublist.Buffers + slidx;
+ return al::to_address(sublist.Buffers->begin() + slidx);
}
@@ -286,7 +288,7 @@ void LoadData(ALCcontext *context, ALbuffer *ALBuf, ALsizei freq, ALuint size,
const FmtChannels DstChannels, const FmtType DstType, const std::byte *SrcData,
ALbitfieldSOFT access)
{
- if(ReadRef(ALBuf->ref) != 0 || ALBuf->MappedAccess != 0) UNLIKELY
+ if(ALBuf->ref.load(std::memory_order_relaxed) != 0 || ALBuf->MappedAccess != 0) UNLIKELY
return context->setError(AL_INVALID_OPERATION, "Modifying storage for in-use buffer %u",
ALBuf->id);
@@ -393,7 +395,7 @@ void PrepareCallback(ALCcontext *context, ALbuffer *ALBuf, ALsizei freq,
const FmtChannels DstChannels, const FmtType DstType, ALBUFFERCALLBACKTYPESOFT callback,
void *userptr)
{
- if(ReadRef(ALBuf->ref) != 0 || ALBuf->MappedAccess != 0) UNLIKELY
+ if(ALBuf->ref.load(std::memory_order_relaxed) != 0 || ALBuf->MappedAccess != 0) UNLIKELY
return context->setError(AL_INVALID_OPERATION, "Modifying callback for in-use buffer %u",
ALBuf->id);
@@ -402,6 +404,10 @@ void PrepareCallback(ALCcontext *context, ALbuffer *ALBuf, ALsizei freq,
const ALuint unpackalign{ALBuf->UnpackAlign};
const ALuint align{SanitizeAlignment(DstType, unpackalign)};
+ if(align < 1) UNLIKELY
+ return context->setError(AL_INVALID_VALUE, "Invalid unpack alignment %u for %s samples",
+ unpackalign, NameFromFormat(DstType));
+
const ALuint BlockSize{ChannelsFromFmt(DstChannels, ambiorder) *
((DstType == FmtIMA4) ? (align-1)/2 + 4 :
(DstType == FmtMSADPCM) ? (align-2)/2 + 7 :
@@ -445,7 +451,7 @@ void PrepareCallback(ALCcontext *context, ALbuffer *ALBuf, ALsizei freq,
void PrepareUserPtr(ALCcontext *context, ALbuffer *ALBuf, ALsizei freq,
const FmtChannels DstChannels, const FmtType DstType, std::byte *sdata, const ALuint sdatalen)
{
- if(ReadRef(ALBuf->ref) != 0 || ALBuf->MappedAccess != 0) UNLIKELY
+ if(ALBuf->ref.load(std::memory_order_relaxed) != 0 || ALBuf->MappedAccess != 0) UNLIKELY
return context->setError(AL_INVALID_OPERATION, "Modifying storage for in-use buffer %u",
ALBuf->id);
@@ -711,7 +717,7 @@ FORCE_ALIGN void AL_APIENTRY alDeleteBuffersDirect(ALCcontext *context, ALsizei
context->setError(AL_INVALID_NAME, "Invalid buffer ID %u", bid);
return false;
}
- if(ReadRef(ALBuf->ref) != 0) UNLIKELY
+ if(ALBuf->ref.load(std::memory_order_relaxed) != 0) UNLIKELY
{
context->setError(AL_INVALID_OPERATION, "Deleting in-use buffer %u", bid);
return false;
@@ -826,7 +832,8 @@ FORCE_ALIGN void* AL_APIENTRY alMapBufferDirectSOFT(ALCcontext *context, ALuint
else
{
ALbitfieldSOFT unavailable = (albuf->Access^access) & access;
- if(ReadRef(albuf->ref) != 0 && !(access&AL_MAP_PERSISTENT_BIT_SOFT)) UNLIKELY
+ if(albuf->ref.load(std::memory_order_relaxed) != 0
+ && !(access&AL_MAP_PERSISTENT_BIT_SOFT)) UNLIKELY
context->setError(AL_INVALID_OPERATION,
"Mapping in-use buffer %u without persistent mapping", buffer);
else if(albuf->MappedAccess != 0) UNLIKELY
@@ -1042,7 +1049,7 @@ FORCE_ALIGN void AL_APIENTRY alBufferiDirect(ALCcontext *context, ALuint buffer,
break;
case AL_AMBISONIC_LAYOUT_SOFT:
- if(ReadRef(albuf->ref) != 0) UNLIKELY
+ if(albuf->ref.load(std::memory_order_relaxed) != 0) UNLIKELY
context->setError(AL_INVALID_OPERATION, "Modifying in-use buffer %u's ambisonic layout",
buffer);
else if(const auto layout = AmbiLayoutFromEnum(value))
@@ -1052,7 +1059,7 @@ FORCE_ALIGN void AL_APIENTRY alBufferiDirect(ALCcontext *context, ALuint buffer,
break;
case AL_AMBISONIC_SCALING_SOFT:
- if(ReadRef(albuf->ref) != 0) UNLIKELY
+ if(albuf->ref.load(std::memory_order_relaxed) != 0) UNLIKELY
context->setError(AL_INVALID_OPERATION, "Modifying in-use buffer %u's ambisonic scaling",
buffer);
else if(const auto scaling = AmbiScalingFromEnum(value))
@@ -1116,7 +1123,7 @@ FORCE_ALIGN void AL_APIENTRY alBufferivDirect(ALCcontext *context, ALuint buffer
else switch(param)
{
case AL_LOOP_POINTS_SOFT:
- if(ReadRef(albuf->ref) != 0) UNLIKELY
+ if(albuf->ref.load(std::memory_order_relaxed) != 0) UNLIKELY
context->setError(AL_INVALID_OPERATION, "Modifying in-use buffer %u's loop points",
buffer);
else if(values[0] < 0 || values[0] >= values[1]
@@ -1366,7 +1373,7 @@ FORCE_ALIGN void AL_APIENTRY alGetBufferPtrDirectSOFT(ALCcontext *context, ALuin
else switch(param)
{
case AL_BUFFER_CALLBACK_FUNCTION_SOFT:
- *value = al::bit_cast<void*>(albuf->mCallback);
+ *value = reinterpret_cast<void*>(albuf->mCallback);
break;
case AL_BUFFER_CALLBACK_USER_PARAM_SOFT:
*value = albuf->mUserData;
@@ -1480,11 +1487,11 @@ BufferSubList::~BufferSubList()
while(usemask)
{
const int idx{al::countr_zero(usemask)};
- std::destroy_at(Buffers+idx);
+ std::destroy_at(al::to_address(Buffers->begin() + idx));
usemask &= ~(1_u64 << idx);
}
FreeMask = ~usemask;
- al_free(Buffers);
+ SubListAllocator{}.deallocate(Buffers, 1);
Buffers = nullptr;
}
diff --git a/al/buffer.h b/al/buffer.h
index f936cf98..b9e59d68 100644
--- a/al/buffer.h
+++ b/al/buffer.h
@@ -3,12 +3,14 @@
#include <atomic>
#include <cstddef>
+#include <cstdint>
#include <string_view>
#include "AL/al.h"
#include "alc/inprogext.h"
#include "almalloc.h"
+#include "alnumeric.h"
#include "atomic.h"
#include "core/buffer_storage.h"
#include "vector.h"
@@ -43,14 +45,14 @@ struct ALbuffer : public BufferStorage {
ALuint mLoopEnd{0u};
/* Number of times buffer was attached to a source (deletion can only occur when 0) */
- RefCount ref{0u};
+ std::atomic<ALuint> ref{0u};
/* Self ID */
ALuint id{0};
static void SetName(ALCcontext *context, ALuint id, std::string_view name);
- DISABLE_ALLOC()
+ DISABLE_ALLOC
#ifdef ALSOFT_EAX
EaxStorage eax_x_ram_mode{EaxStorage::Automatic};
@@ -58,4 +60,19 @@ struct ALbuffer : public BufferStorage {
#endif // ALSOFT_EAX
};
+struct BufferSubList {
+ uint64_t FreeMask{~0_u64};
+ gsl::owner<std::array<ALbuffer,64>*> Buffers{nullptr};
+
+ 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; }
+};
+
#endif
diff --git a/al/debug.cpp b/al/debug.cpp
index b76ec9af..cd79c148 100644
--- a/al/debug.cpp
+++ b/al/debug.cpp
@@ -4,10 +4,10 @@
#include <algorithm>
#include <array>
+#include <cstddef>
#include <cstring>
#include <mutex>
#include <optional>
-#include <stddef.h>
#include <stdexcept>
#include <string>
#include <utility>
diff --git a/al/direct_defs.h b/al/direct_defs.h
index 7526b611..a1999668 100644
--- a/al/direct_defs.h
+++ b/al/direct_defs.h
@@ -12,7 +12,7 @@ constexpr void DefaultVal() noexcept { }
} // namespace detail_
#define DECL_FUNC(R, Name) \
-R AL_APIENTRY Name(void) noexcept \
+auto AL_APIENTRY Name() noexcept -> R \
{ \
auto context = GetContextRef(); \
if(!context) UNLIKELY return detail_::DefaultVal<R>(); \
@@ -20,7 +20,7 @@ R AL_APIENTRY Name(void) noexcept \
}
#define DECL_FUNC1(R, Name, T1) \
-R AL_APIENTRY Name(T1 a) noexcept \
+auto AL_APIENTRY Name(T1 a) noexcept -> R \
{ \
auto context = GetContextRef(); \
if(!context) UNLIKELY return detail_::DefaultVal<R>(); \
@@ -28,7 +28,7 @@ R AL_APIENTRY Name(T1 a) noexcept \
}
#define DECL_FUNC2(R, Name, T1, T2) \
-R AL_APIENTRY Name(T1 a, T2 b) noexcept \
+auto AL_APIENTRY Name(T1 a, T2 b) noexcept -> R \
{ \
auto context = GetContextRef(); \
if(!context) UNLIKELY return detail_::DefaultVal<R>(); \
@@ -36,7 +36,7 @@ R AL_APIENTRY Name(T1 a, T2 b) noexcept \
}
#define DECL_FUNC3(R, Name, T1, T2, T3) \
-R AL_APIENTRY Name(T1 a, T2 b, T3 c) noexcept \
+auto AL_APIENTRY Name(T1 a, T2 b, T3 c) noexcept -> R \
{ \
auto context = GetContextRef(); \
if(!context) UNLIKELY return detail_::DefaultVal<R>(); \
@@ -44,7 +44,7 @@ R AL_APIENTRY Name(T1 a, T2 b, T3 c) noexcept \
}
#define DECL_FUNC4(R, Name, T1, T2, T3, T4) \
-R AL_APIENTRY Name(T1 a, T2 b, T3 c, T4 d) noexcept \
+auto AL_APIENTRY Name(T1 a, T2 b, T3 c, T4 d) noexcept -> R \
{ \
auto context = GetContextRef(); \
if(!context) UNLIKELY return detail_::DefaultVal<R>(); \
@@ -52,7 +52,7 @@ R AL_APIENTRY Name(T1 a, T2 b, T3 c, T4 d) noexcept \
}
#define DECL_FUNC5(R, Name, T1, T2, T3, T4, T5) \
-R AL_APIENTRY Name(T1 a, T2 b, T3 c, T4 d, T5 e) noexcept \
+auto AL_APIENTRY Name(T1 a, T2 b, T3 c, T4 d, T5 e) noexcept -> R \
{ \
auto context = GetContextRef(); \
if(!context) UNLIKELY return detail_::DefaultVal<R>(); \
@@ -61,7 +61,7 @@ R AL_APIENTRY Name(T1 a, T2 b, T3 c, T4 d, T5 e) noexcept \
#define DECL_FUNCEXT(R, Name,Ext) \
-R AL_APIENTRY Name##Ext(void) noexcept \
+auto AL_APIENTRY Name##Ext() noexcept -> R \
{ \
auto context = GetContextRef(); \
if(!context) UNLIKELY return detail_::DefaultVal<R>(); \
@@ -69,7 +69,7 @@ R AL_APIENTRY Name##Ext(void) noexcept \
}
#define DECL_FUNCEXT1(R, Name,Ext, T1) \
-R AL_APIENTRY Name##Ext(T1 a) noexcept \
+auto AL_APIENTRY Name##Ext(T1 a) noexcept -> R \
{ \
auto context = GetContextRef(); \
if(!context) UNLIKELY return detail_::DefaultVal<R>(); \
@@ -77,7 +77,7 @@ R AL_APIENTRY Name##Ext(T1 a) noexcept \
}
#define DECL_FUNCEXT2(R, Name,Ext, T1, T2) \
-R AL_APIENTRY Name##Ext(T1 a, T2 b) noexcept \
+auto AL_APIENTRY Name##Ext(T1 a, T2 b) noexcept -> R \
{ \
auto context = GetContextRef(); \
if(!context) UNLIKELY return detail_::DefaultVal<R>(); \
@@ -85,7 +85,7 @@ R AL_APIENTRY Name##Ext(T1 a, T2 b) noexcept \
}
#define DECL_FUNCEXT3(R, Name,Ext, T1, T2, T3) \
-R AL_APIENTRY Name##Ext(T1 a, T2 b, T3 c) noexcept \
+auto AL_APIENTRY Name##Ext(T1 a, T2 b, T3 c) noexcept -> R \
{ \
auto context = GetContextRef(); \
if(!context) UNLIKELY return detail_::DefaultVal<R>(); \
@@ -93,7 +93,7 @@ R AL_APIENTRY Name##Ext(T1 a, T2 b, T3 c) noexcept \
}
#define DECL_FUNCEXT4(R, Name,Ext, T1, T2, T3, T4) \
-R AL_APIENTRY Name##Ext(T1 a, T2 b, T3 c, T4 d) noexcept \
+auto AL_APIENTRY Name##Ext(T1 a, T2 b, T3 c, T4 d) noexcept -> R \
{ \
auto context = GetContextRef(); \
if(!context) UNLIKELY return detail_::DefaultVal<R>(); \
@@ -101,7 +101,7 @@ R AL_APIENTRY Name##Ext(T1 a, T2 b, T3 c, T4 d) noexcept \
}
#define DECL_FUNCEXT5(R, Name,Ext, T1, T2, T3, T4, T5) \
-R AL_APIENTRY Name##Ext(T1 a, T2 b, T3 c, T4 d, T5 e) noexcept \
+auto AL_APIENTRY Name##Ext(T1 a, T2 b, T3 c, T4 d, T5 e) noexcept -> R \
{ \
auto context = GetContextRef(); \
if(!context) UNLIKELY return detail_::DefaultVal<R>(); \
@@ -109,7 +109,7 @@ R AL_APIENTRY Name##Ext(T1 a, T2 b, T3 c, T4 d, T5 e) noexcept \
}
#define DECL_FUNCEXT6(R, Name,Ext, T1, T2, T3, T4, T5, T6) \
-R AL_APIENTRY Name##Ext(T1 a, T2 b, T3 c, T4 d, T5 e, T6 f) noexcept \
+auto AL_APIENTRY Name##Ext(T1 a, T2 b, T3 c, T4 d, T5 e, T6 f) noexcept -> R \
{ \
auto context = GetContextRef(); \
if(!context) UNLIKELY return detail_::DefaultVal<R>(); \
@@ -117,7 +117,7 @@ R AL_APIENTRY Name##Ext(T1 a, T2 b, T3 c, T4 d, T5 e, T6 f) noexcept \
}
#define DECL_FUNCEXT8(R, Name,Ext, T1, T2, T3, T4, T5, T6, T7, T8) \
-R AL_APIENTRY Name##Ext(T1 a, T2 b, T3 c, T4 d, T5 e, T6 f, T7 g, T8 h) noexcept \
+auto AL_APIENTRY Name##Ext(T1 a, T2 b, T3 c, T4 d, T5 e, T6 f, T7 g, T8 h) noexcept -> R \
{ \
auto context = GetContextRef(); \
if(!context) UNLIKELY return detail_::DefaultVal<R>(); \
diff --git a/al/eax/api.h b/al/eax/api.h
index 18d93ef8..0b019f11 100644
--- a/al/eax/api.h
+++ b/al/eax/api.h
@@ -22,12 +22,12 @@
#ifndef _WIN32
-typedef struct _GUID {
+using GUID = struct _GUID {
std::uint32_t Data1;
std::uint16_t Data2;
std::uint16_t Data3;
- std::uint8_t Data4[8];
-} GUID;
+ std::array<std::uint8_t,8> Data4;
+};
inline bool operator==(const GUID& lhs, const GUID& rhs) noexcept
{ return std::memcmp(&lhs, &rhs, sizeof(GUID)) == 0; }
@@ -362,6 +362,7 @@ constexpr auto EAXCONTEXT_MINMACROFXFACTOR = 0.0F;
constexpr auto EAXCONTEXT_MAXMACROFXFACTOR = 1.0F;
constexpr auto EAXCONTEXT_DEFAULTMACROFXFACTOR = 0.0F;
+constexpr auto EAXCONTEXT_DEFAULTLASTERROR = EAX_OK;
extern const GUID EAXPROPERTYID_EAX40_FXSlot0;
extern const GUID EAXPROPERTYID_EAX50_FXSlot0;
@@ -654,11 +655,11 @@ struct EAXSPEAKERLEVELPROPERTIES {
}; // EAXSPEAKERLEVELPROPERTIES
struct EAX40ACTIVEFXSLOTS {
- GUID guidActiveFXSlots[EAX40_MAX_ACTIVE_FXSLOTS];
+ std::array<GUID,EAX40_MAX_ACTIVE_FXSLOTS> guidActiveFXSlots;
}; // EAX40ACTIVEFXSLOTS
struct EAX50ACTIVEFXSLOTS {
- GUID guidActiveFXSlots[EAX50_MAX_ACTIVE_FXSLOTS];
+ std::array<GUID,EAX50_MAX_ACTIVE_FXSLOTS> guidActiveFXSlots;
}; // EAX50ACTIVEFXSLOTS
// Use this structure for EAXSOURCE_OBSTRUCTIONPARAMETERS property.
diff --git a/al/eax/call.cpp b/al/eax/call.cpp
index 689d5cf1..013a3992 100644
--- a/al/eax/call.cpp
+++ b/al/eax/call.cpp
@@ -22,8 +22,7 @@ EaxCall::EaxCall(
ALuint property_source_id,
ALvoid* property_buffer,
ALuint property_size)
- : mCallType{type}, mVersion{0}, mPropertySetId{EaxCallPropertySetId::none}
- , mIsDeferred{(property_id & deferred_flag) != 0}
+ : mCallType{type}, mIsDeferred{(property_id & deferred_flag) != 0}
, mPropertyId{property_id & ~deferred_flag}, mPropertySourceId{property_source_id}
, mPropertyBuffer{property_buffer}, mPropertyBufferSize{property_size}
{
diff --git a/al/eax/call.h b/al/eax/call.h
index 45ff328c..e7f2329f 100644
--- a/al/eax/call.h
+++ b/al/eax/call.h
@@ -31,16 +31,16 @@ public:
ALvoid* property_buffer,
ALuint property_size);
- bool is_get() const noexcept { return mCallType == EaxCallType::get; }
- bool is_deferred() const noexcept { return mIsDeferred; }
- int get_version() const noexcept { return mVersion; }
- EaxCallPropertySetId get_property_set_id() const noexcept { return mPropertySetId; }
- ALuint get_property_id() const noexcept { return mPropertyId; }
- ALuint get_property_al_name() const noexcept { return mPropertySourceId; }
- EaxFxSlotIndex get_fx_slot_index() const noexcept { return mFxSlotIndex; }
+ [[nodiscard]] auto is_get() const noexcept -> bool { return mCallType == EaxCallType::get; }
+ [[nodiscard]] auto is_deferred() const noexcept -> bool { return mIsDeferred; }
+ [[nodiscard]] auto get_version() const noexcept -> int { return mVersion; }
+ [[nodiscard]] auto get_property_set_id() const noexcept -> EaxCallPropertySetId { return mPropertySetId; }
+ [[nodiscard]] auto get_property_id() const noexcept -> ALuint { return mPropertyId; }
+ [[nodiscard]] auto get_property_al_name() const noexcept -> ALuint { return mPropertySourceId; }
+ [[nodiscard]] auto get_fx_slot_index() const noexcept -> EaxFxSlotIndex { return mFxSlotIndex; }
template<typename TException, typename TValue>
- TValue& get_value() const
+ [[nodiscard]] auto get_value() const -> TValue&
{
if(mPropertyBufferSize < sizeof(TValue))
fail_too_small();
@@ -49,7 +49,7 @@ public:
}
template<typename TValue>
- al::span<TValue> get_values(size_t max_count) const
+ [[nodiscard]] auto get_values(size_t max_count) const -> al::span<TValue>
{
if(max_count == 0 || mPropertyBufferSize < sizeof(TValue))
fail_too_small();
@@ -59,22 +59,22 @@ public:
}
template<typename TValue>
- al::span<TValue> get_values() const
+ [[nodiscard]] auto get_values() const -> al::span<TValue>
{
return get_values<TValue>(~0_uz);
}
template<typename TException, typename TValue>
- void set_value(const TValue& value) const
+ auto set_value(const TValue& value) const -> void
{
get_value<TException, TValue>() = value;
}
private:
const EaxCallType mCallType;
- int mVersion;
- EaxFxSlotIndex mFxSlotIndex;
- EaxCallPropertySetId mPropertySetId;
+ int mVersion{};
+ EaxFxSlotIndex mFxSlotIndex{};
+ EaxCallPropertySetId mPropertySetId{EaxCallPropertySetId::none};
bool mIsDeferred;
const ALuint mPropertyId;
diff --git a/al/eax/effect.h b/al/eax/effect.h
index afe4d94d..a735fe6c 100644
--- a/al/eax/effect.h
+++ b/al/eax/effect.h
@@ -100,7 +100,6 @@ struct EaxReverbCommitter {
bool commit(const EAX_REVERBPROPERTIES &props);
bool commit(const EAX20LISTENERPROPERTIES &props);
bool commit(const EAXREVERBPROPERTIES &props);
- bool commit(const EaxEffectProps &props);
static void SetDefaults(EAX_REVERBPROPERTIES &props);
static void SetDefaults(EAX20LISTENERPROPERTIES &props);
@@ -110,16 +109,13 @@ struct EaxReverbCommitter {
static void Get(const EaxCall &call, const EAX_REVERBPROPERTIES &props);
static void Get(const EaxCall &call, const EAX20LISTENERPROPERTIES &props);
static void Get(const EaxCall &call, const EAXREVERBPROPERTIES &props);
- static void Get(const EaxCall &call, const EaxEffectProps &props);
static void Set(const EaxCall &call, EAX_REVERBPROPERTIES &props);
static void Set(const EaxCall &call, EAX20LISTENERPROPERTIES &props);
static void Set(const EaxCall &call, EAXREVERBPROPERTIES &props);
- static void Set(const EaxCall &call, EaxEffectProps &props);
- static void translate(const EAX_REVERBPROPERTIES& src, EaxEffectProps& dst) noexcept;
- static void translate(const EAX20LISTENERPROPERTIES& src, EaxEffectProps& dst) noexcept;
- static void translate(const EAXREVERBPROPERTIES& src, EaxEffectProps& dst) noexcept;
+ static void translate(const EAX_REVERBPROPERTIES& src, EAXREVERBPROPERTIES& dst) noexcept;
+ static void translate(const EAX20LISTENERPROPERTIES& src, EAXREVERBPROPERTIES& dst) noexcept;
};
template<typename T>
@@ -144,51 +140,137 @@ struct EaxCommitter {
[[noreturn]] static void fail(const char *message);
[[noreturn]] static void fail_unknown_property_id()
{ fail(EaxEffectErrorMessages::unknown_property_id()); }
-
- bool commit(const EaxEffectProps &props);
-
- static void SetDefaults(EaxEffectProps &props);
- static void Get(const EaxCall &call, const EaxEffectProps &props);
- static void Set(const EaxCall &call, EaxEffectProps &props);
};
struct EaxAutowahCommitter : public EaxCommitter<EaxAutowahCommitter> {
using EaxCommitter<EaxAutowahCommitter>::EaxCommitter;
+
+ bool commit(const EAXAUTOWAHPROPERTIES &props);
+
+ static void SetDefaults(EaxEffectProps &props);
+ static void Get(const EaxCall &call, const EAXAUTOWAHPROPERTIES &props);
+ static void Set(const EaxCall &call, EAXAUTOWAHPROPERTIES &props);
};
struct EaxChorusCommitter : public EaxCommitter<EaxChorusCommitter> {
using EaxCommitter<EaxChorusCommitter>::EaxCommitter;
+
+ bool commit(const EAXCHORUSPROPERTIES &props);
+
+ static void SetDefaults(EaxEffectProps &props);
+ static void Get(const EaxCall &call, const EAXCHORUSPROPERTIES &props);
+ static void Set(const EaxCall &call, EAXCHORUSPROPERTIES &props);
};
struct EaxCompressorCommitter : public EaxCommitter<EaxCompressorCommitter> {
using EaxCommitter<EaxCompressorCommitter>::EaxCommitter;
+
+ bool commit(const EAXAGCCOMPRESSORPROPERTIES &props);
+
+ static void SetDefaults(EaxEffectProps &props);
+ static void Get(const EaxCall &call, const EAXAGCCOMPRESSORPROPERTIES &props);
+ static void Set(const EaxCall &call, EAXAGCCOMPRESSORPROPERTIES &props);
};
struct EaxDistortionCommitter : public EaxCommitter<EaxDistortionCommitter> {
using EaxCommitter<EaxDistortionCommitter>::EaxCommitter;
+
+ bool commit(const EAXDISTORTIONPROPERTIES &props);
+
+ static void SetDefaults(EaxEffectProps &props);
+ static void Get(const EaxCall &call, const EAXDISTORTIONPROPERTIES &props);
+ static void Set(const EaxCall &call, EAXDISTORTIONPROPERTIES &props);
};
struct EaxEchoCommitter : public EaxCommitter<EaxEchoCommitter> {
using EaxCommitter<EaxEchoCommitter>::EaxCommitter;
+
+ bool commit(const EAXECHOPROPERTIES &props);
+
+ static void SetDefaults(EaxEffectProps &props);
+ static void Get(const EaxCall &call, const EAXECHOPROPERTIES &props);
+ static void Set(const EaxCall &call, EAXECHOPROPERTIES &props);
};
struct EaxEqualizerCommitter : public EaxCommitter<EaxEqualizerCommitter> {
using EaxCommitter<EaxEqualizerCommitter>::EaxCommitter;
+
+ bool commit(const EAXEQUALIZERPROPERTIES &props);
+
+ static void SetDefaults(EaxEffectProps &props);
+ static void Get(const EaxCall &call, const EAXEQUALIZERPROPERTIES &props);
+ static void Set(const EaxCall &call, EAXEQUALIZERPROPERTIES &props);
};
struct EaxFlangerCommitter : public EaxCommitter<EaxFlangerCommitter> {
using EaxCommitter<EaxFlangerCommitter>::EaxCommitter;
+
+ bool commit(const EAXFLANGERPROPERTIES &props);
+
+ static void SetDefaults(EaxEffectProps &props);
+ static void Get(const EaxCall &call, const EAXFLANGERPROPERTIES &props);
+ static void Set(const EaxCall &call, EAXFLANGERPROPERTIES &props);
};
struct EaxFrequencyShifterCommitter : public EaxCommitter<EaxFrequencyShifterCommitter> {
using EaxCommitter<EaxFrequencyShifterCommitter>::EaxCommitter;
+
+ bool commit(const EAXFREQUENCYSHIFTERPROPERTIES &props);
+
+ static void SetDefaults(EaxEffectProps &props);
+ static void Get(const EaxCall &call, const EAXFREQUENCYSHIFTERPROPERTIES &props);
+ static void Set(const EaxCall &call, EAXFREQUENCYSHIFTERPROPERTIES &props);
};
struct EaxModulatorCommitter : public EaxCommitter<EaxModulatorCommitter> {
using EaxCommitter<EaxModulatorCommitter>::EaxCommitter;
+
+ bool commit(const EAXRINGMODULATORPROPERTIES &props);
+
+ static void SetDefaults(EaxEffectProps &props);
+ static void Get(const EaxCall &call, const EAXRINGMODULATORPROPERTIES &props);
+ static void Set(const EaxCall &call, EAXRINGMODULATORPROPERTIES &props);
};
struct EaxPitchShifterCommitter : public EaxCommitter<EaxPitchShifterCommitter> {
using EaxCommitter<EaxPitchShifterCommitter>::EaxCommitter;
+
+ bool commit(const EAXPITCHSHIFTERPROPERTIES &props);
+
+ static void SetDefaults(EaxEffectProps &props);
+ static void Get(const EaxCall &call, const EAXPITCHSHIFTERPROPERTIES &props);
+ static void Set(const EaxCall &call, EAXPITCHSHIFTERPROPERTIES &props);
};
struct EaxVocalMorpherCommitter : public EaxCommitter<EaxVocalMorpherCommitter> {
using EaxCommitter<EaxVocalMorpherCommitter>::EaxCommitter;
+
+ bool commit(const EAXVOCALMORPHERPROPERTIES &props);
+
+ static void SetDefaults(EaxEffectProps &props);
+ static void Get(const EaxCall &call, const EAXVOCALMORPHERPROPERTIES &props);
+ static void Set(const EaxCall &call, EAXVOCALMORPHERPROPERTIES &props);
};
struct EaxNullCommitter : public EaxCommitter<EaxNullCommitter> {
using EaxCommitter<EaxNullCommitter>::EaxCommitter;
+
+ bool commit(const std::monostate &props);
+
+ static void SetDefaults(EaxEffectProps &props);
+ static void Get(const EaxCall &call, const std::monostate &props);
+ static void Set(const EaxCall &call, std::monostate &props);
};
+template<typename T>
+struct CommitterFromProps { };
+
+template<> struct CommitterFromProps<std::monostate> { using type = EaxNullCommitter; };
+template<> struct CommitterFromProps<EAXREVERBPROPERTIES> { using type = EaxReverbCommitter; };
+template<> struct CommitterFromProps<EAXCHORUSPROPERTIES> { using type = EaxChorusCommitter; };
+template<> struct CommitterFromProps<EAXAGCCOMPRESSORPROPERTIES> { using type = EaxCompressorCommitter; };
+template<> struct CommitterFromProps<EAXAUTOWAHPROPERTIES> { using type = EaxAutowahCommitter; };
+template<> struct CommitterFromProps<EAXDISTORTIONPROPERTIES> { using type = EaxDistortionCommitter; };
+template<> struct CommitterFromProps<EAXECHOPROPERTIES> { using type = EaxEchoCommitter; };
+template<> struct CommitterFromProps<EAXEQUALIZERPROPERTIES> { using type = EaxEqualizerCommitter; };
+template<> struct CommitterFromProps<EAXFLANGERPROPERTIES> { using type = EaxFlangerCommitter; };
+template<> struct CommitterFromProps<EAXFREQUENCYSHIFTERPROPERTIES> { using type = EaxFrequencyShifterCommitter; };
+template<> struct CommitterFromProps<EAXRINGMODULATORPROPERTIES> { using type = EaxModulatorCommitter; };
+template<> struct CommitterFromProps<EAXPITCHSHIFTERPROPERTIES> { using type = EaxPitchShifterCommitter; };
+template<> struct CommitterFromProps<EAXVOCALMORPHERPROPERTIES> { using type = EaxVocalMorpherCommitter; };
+
+template<typename T>
+using CommitterFor = typename CommitterFromProps<std::remove_cv_t<std::remove_reference_t<T>>>::type;
+
class EaxEffect {
public:
@@ -233,51 +315,39 @@ public:
State4 state5_{};
- template<typename T, typename ...Args>
- void call_set_defaults(Args&& ...args)
- { return T::SetDefaults(std::forward<Args>(args)...); }
-
void call_set_defaults(const ALenum altype, EaxEffectProps &props)
{
- if(altype == AL_EFFECT_EAXREVERB)
- return call_set_defaults<EaxReverbCommitter>(props);
- if(altype == AL_EFFECT_CHORUS)
- return call_set_defaults<EaxChorusCommitter>(props);
- if(altype == AL_EFFECT_AUTOWAH)
- return call_set_defaults<EaxAutowahCommitter>(props);
- if(altype == AL_EFFECT_COMPRESSOR)
- return call_set_defaults<EaxCompressorCommitter>(props);
- if(altype == AL_EFFECT_DISTORTION)
- return call_set_defaults<EaxDistortionCommitter>(props);
- if(altype == AL_EFFECT_ECHO)
- return call_set_defaults<EaxEchoCommitter>(props);
- if(altype == AL_EFFECT_EQUALIZER)
- return call_set_defaults<EaxEqualizerCommitter>(props);
- if(altype == AL_EFFECT_FLANGER)
- return call_set_defaults<EaxFlangerCommitter>(props);
- if(altype == AL_EFFECT_FREQUENCY_SHIFTER)
- return call_set_defaults<EaxFrequencyShifterCommitter>(props);
- if(altype == AL_EFFECT_RING_MODULATOR)
- return call_set_defaults<EaxModulatorCommitter>(props);
- if(altype == AL_EFFECT_PITCH_SHIFTER)
- return call_set_defaults<EaxPitchShifterCommitter>(props);
- if(altype == AL_EFFECT_VOCAL_MORPHER)
- return call_set_defaults<EaxVocalMorpherCommitter>(props);
- return call_set_defaults<EaxNullCommitter>(props);
+ switch(altype)
+ {
+ case AL_EFFECT_EAXREVERB: return EaxReverbCommitter::SetDefaults(props);
+ case AL_EFFECT_CHORUS: return EaxChorusCommitter::SetDefaults(props);
+ case AL_EFFECT_AUTOWAH: return EaxAutowahCommitter::SetDefaults(props);
+ case AL_EFFECT_COMPRESSOR: return EaxCompressorCommitter::SetDefaults(props);
+ case AL_EFFECT_DISTORTION: return EaxDistortionCommitter::SetDefaults(props);
+ case AL_EFFECT_ECHO: return EaxEchoCommitter::SetDefaults(props);
+ case AL_EFFECT_EQUALIZER: return EaxEqualizerCommitter::SetDefaults(props);
+ case AL_EFFECT_FLANGER: return EaxFlangerCommitter::SetDefaults(props);
+ case AL_EFFECT_FREQUENCY_SHIFTER: return EaxFrequencyShifterCommitter::SetDefaults(props);
+ case AL_EFFECT_RING_MODULATOR: return EaxModulatorCommitter::SetDefaults(props);
+ case AL_EFFECT_PITCH_SHIFTER: return EaxPitchShifterCommitter::SetDefaults(props);
+ case AL_EFFECT_VOCAL_MORPHER: return EaxVocalMorpherCommitter::SetDefaults(props);
+ case AL_EFFECT_NULL: break;
+ }
+ return EaxNullCommitter::SetDefaults(props);
}
template<typename T>
void init()
{
- call_set_defaults<EaxReverbCommitter>(state1_.d);
+ EaxReverbCommitter::SetDefaults(state1_.d);
state1_.i = state1_.d;
- call_set_defaults<EaxReverbCommitter>(state2_.d);
+ EaxReverbCommitter::SetDefaults(state2_.d);
state2_.i = state2_.d;
- call_set_defaults<EaxReverbCommitter>(state3_.d);
+ EaxReverbCommitter::SetDefaults(state3_.d);
state3_.i = state3_.d;
- call_set_defaults<T>(state4_.d);
+ T::SetDefaults(state4_.d);
state4_.i = state4_.d;
- call_set_defaults<T>(state5_.d);
+ T::SetDefaults(state5_.d);
state5_.i = state5_.d;
}
@@ -285,9 +355,9 @@ public:
{
switch(eax_version)
{
- case 1: call_set_defaults<EaxReverbCommitter>(state1_.d); break;
- case 2: call_set_defaults<EaxReverbCommitter>(state2_.d); break;
- case 3: call_set_defaults<EaxReverbCommitter>(state3_.d); break;
+ case 1: EaxReverbCommitter::SetDefaults(state1_.d); break;
+ case 2: EaxReverbCommitter::SetDefaults(state2_.d); break;
+ case 3: EaxReverbCommitter::SetDefaults(state3_.d); break;
case 4: call_set_defaults(altype, state4_.d); break;
case 5: call_set_defaults(altype, state5_.d); break;
}
@@ -295,47 +365,20 @@ public:
}
-#define EAXCALL(Props, Callable, ...) \
- if(std::holds_alternative<EAXREVERBPROPERTIES>(Props)) \
- return Callable<EaxReverbCommitter>(__VA_ARGS__); \
- if(std::holds_alternative<EAXCHORUSPROPERTIES>(Props)) \
- return Callable<EaxChorusCommitter>(__VA_ARGS__); \
- if(std::holds_alternative<EAXAUTOWAHPROPERTIES>(Props)) \
- return Callable<EaxAutowahCommitter>(__VA_ARGS__); \
- if(std::holds_alternative<EAXAGCCOMPRESSORPROPERTIES>(Props)) \
- return Callable<EaxCompressorCommitter>(__VA_ARGS__); \
- if(std::holds_alternative<EAXDISTORTIONPROPERTIES>(Props)) \
- return Callable<EaxDistortionCommitter>(__VA_ARGS__); \
- if(std::holds_alternative<EAXECHOPROPERTIES>(Props)) \
- return Callable<EaxEchoCommitter>(__VA_ARGS__); \
- if(std::holds_alternative<EAXEQUALIZERPROPERTIES>(Props)) \
- return Callable<EaxEqualizerCommitter>(__VA_ARGS__); \
- if(std::holds_alternative<EAXFLANGERPROPERTIES>(Props)) \
- return Callable<EaxFlangerCommitter>(__VA_ARGS__); \
- if(std::holds_alternative<EAXFREQUENCYSHIFTERPROPERTIES>(Props)) \
- return Callable<EaxFrequencyShifterCommitter>(__VA_ARGS__); \
- if(std::holds_alternative<EAXRINGMODULATORPROPERTIES>(Props)) \
- return Callable<EaxModulatorCommitter>(__VA_ARGS__); \
- if(std::holds_alternative<EAXPITCHSHIFTERPROPERTIES>(Props)) \
- return Callable<EaxPitchShifterCommitter>(__VA_ARGS__); \
- if(std::holds_alternative<EAXVOCALMORPHERPROPERTIES>(Props)) \
- return Callable<EaxVocalMorpherCommitter>(__VA_ARGS__); \
- return Callable<EaxNullCommitter>(__VA_ARGS__)
-
- template<typename T, typename ...Args>
- static void call_set(Args&& ...args)
- { return T::Set(std::forward<Args>(args)...); }
-
static void call_set(const EaxCall &call, EaxEffectProps &props)
- { EAXCALL(props, call_set, call, props); }
+ {
+ return std::visit([&](auto &arg)
+ { return CommitterFor<decltype(arg)>::Set(call, arg); },
+ props);
+ }
void set(const EaxCall &call)
{
switch(call.get_version())
{
- case 1: call_set<EaxReverbCommitter>(call, state1_.d); break;
- case 2: call_set<EaxReverbCommitter>(call, state2_.d); break;
- case 3: call_set<EaxReverbCommitter>(call, state3_.d); break;
+ case 1: EaxReverbCommitter::Set(call, state1_.d); break;
+ case 2: EaxReverbCommitter::Set(call, state2_.d); break;
+ case 3: EaxReverbCommitter::Set(call, state3_.d); break;
case 4: call_set(call, state4_.d); break;
case 5: call_set(call, state5_.d); break;
}
@@ -343,32 +386,32 @@ public:
}
- template<typename T, typename ...Args>
- static void call_get(Args&& ...args)
- { return T::Get(std::forward<Args>(args)...); }
-
static void call_get(const EaxCall &call, const EaxEffectProps &props)
- { EAXCALL(props, call_get, call, props); }
+ {
+ return std::visit([&](auto &arg)
+ { return CommitterFor<decltype(arg)>::Get(call, arg); },
+ props);
+ }
void get(const EaxCall &call)
{
switch(call.get_version())
{
- case 1: call_get<EaxReverbCommitter>(call, state1_.d); break;
- case 2: call_get<EaxReverbCommitter>(call, state2_.d); break;
- case 3: call_get<EaxReverbCommitter>(call, state3_.d); break;
+ case 1: EaxReverbCommitter::Get(call, state1_.d); break;
+ case 2: EaxReverbCommitter::Get(call, state2_.d); break;
+ case 3: EaxReverbCommitter::Get(call, state3_.d); break;
case 4: call_get(call, state4_.d); break;
case 5: call_get(call, state5_.d); break;
}
}
- template<typename T, typename ...Args>
- bool call_commit(Args&& ...args)
- { return T{props_, al_effect_props_}.commit(std::forward<Args>(args)...); }
-
bool call_commit(const EaxEffectProps &props)
- { EAXCALL(props, call_commit, props); }
+ {
+ return std::visit([&](auto &arg)
+ { return CommitterFor<decltype(arg)>{props_, al_effect_props_}.commit(arg); },
+ props);
+ }
bool commit(int eax_version)
{
@@ -383,15 +426,15 @@ public:
{
case 1:
state1_.i = state1_.d;
- ret |= call_commit<EaxReverbCommitter>(state1_.d);
+ ret |= EaxReverbCommitter{props_, al_effect_props_}.commit(state1_.d);
break;
case 2:
state2_.i = state2_.d;
- ret |= call_commit<EaxReverbCommitter>(state2_.d);
+ ret |= EaxReverbCommitter{props_, al_effect_props_}.commit(state2_.d);
break;
case 3:
state3_.i = state3_.d;
- ret |= call_commit<EaxReverbCommitter>(state3_.d);
+ ret |= EaxReverbCommitter{props_, al_effect_props_}.commit(state3_.d);
break;
case 4:
state4_.i = state4_.d;
diff --git a/al/eax/fx_slots.h b/al/eax/fx_slots.h
index 18b2d3ad..b7ed1031 100644
--- a/al/eax/fx_slots.h
+++ b/al/eax/fx_slots.h
@@ -25,11 +25,9 @@ public:
}
- const ALeffectslot& get(
- EaxFxSlotIndex index) const;
+ [[nodiscard]] auto get(EaxFxSlotIndex index) const -> const ALeffectslot&;
- ALeffectslot& get(
- EaxFxSlotIndex index);
+ [[nodiscard]] auto get(EaxFxSlotIndex index) -> ALeffectslot&;
private:
using Items = std::array<EaxAlEffectSlotUPtr, EAX_MAX_FXSLOTS>;
@@ -39,8 +37,7 @@ private:
[[noreturn]]
- static void fail(
- const char* message);
+ static void fail(const char* message);
void initialize_fx_slots(ALCcontext& al_context);
}; // EaxFxSlots
diff --git a/al/eax/globals.h b/al/eax/globals.h
index ff05d009..4d501ff9 100644
--- a/al/eax/globals.h
+++ b/al/eax/globals.h
@@ -3,6 +3,7 @@
inline bool eax_g_is_enabled{true};
+/* NOLINTBEGIN(*-avoid-c-arrays) */
inline constexpr char eax1_ext_name[]{"EAX"};
inline constexpr char eax2_ext_name[]{"EAX2.0"};
inline constexpr char eax3_ext_name[]{"EAX3.0"};
@@ -16,5 +17,6 @@ inline constexpr char eax_eax_get_func_name[]{"EAXGet"};
inline constexpr char eax_eax_set_buffer_mode_func_name[]{"EAXSetBufferMode"};
inline constexpr char eax_eax_get_buffer_mode_func_name[]{"EAXGetBufferMode"};
+/* NOLINTEND(*-avoid-c-arrays) */
#endif // !EAX_GLOBALS_INCLUDED
diff --git a/al/effect.cpp b/al/effect.cpp
index 3e48e91b..071b32c6 100644
--- a/al/effect.cpp
+++ b/al/effect.cpp
@@ -58,7 +58,7 @@
#include "eax/exception.h"
#endif // ALSOFT_EAX
-const EffectList gEffectList[16]{
+const std::array<EffectList,16> gEffectList{{
{ "eaxreverb", EAXREVERB_EFFECT, AL_EFFECT_EAXREVERB },
{ "reverb", REVERB_EFFECT, AL_EFFECT_REVERB },
{ "autowah", AUTOWAH_EFFECT, AL_EFFECT_AUTOWAH },
@@ -75,9 +75,7 @@ const EffectList gEffectList[16]{
{ "dedicated", DEDICATED_EFFECT, AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT },
{ "dedicated", DEDICATED_EFFECT, AL_EFFECT_DEDICATED_DIALOGUE },
{ "convolution", CONVOLUTION_EFFECT, AL_EFFECT_CONVOLUTION_SOFT },
-};
-
-bool DisabledEffects[MAX_EFFECTS];
+}};
effect_exception::effect_exception(ALenum code, const char *msg, ...) : mErrorCode{code}
@@ -91,72 +89,36 @@ effect_exception::~effect_exception() = default;
namespace {
-struct EffectPropsItem {
- ALenum Type;
- const EffectProps &DefaultProps;
- const EffectVtable &Vtable;
-};
-constexpr EffectPropsItem EffectPropsList[] = {
- { AL_EFFECT_NULL, NullEffectProps, NullEffectVtable },
- { AL_EFFECT_EAXREVERB, ReverbEffectProps, ReverbEffectVtable },
- { AL_EFFECT_REVERB, StdReverbEffectProps, StdReverbEffectVtable },
- { AL_EFFECT_AUTOWAH, AutowahEffectProps, AutowahEffectVtable },
- { AL_EFFECT_CHORUS, ChorusEffectProps, ChorusEffectVtable },
- { AL_EFFECT_COMPRESSOR, CompressorEffectProps, CompressorEffectVtable },
- { AL_EFFECT_DISTORTION, DistortionEffectProps, DistortionEffectVtable },
- { AL_EFFECT_ECHO, EchoEffectProps, EchoEffectVtable },
- { AL_EFFECT_EQUALIZER, EqualizerEffectProps, EqualizerEffectVtable },
- { AL_EFFECT_FLANGER, FlangerEffectProps, FlangerEffectVtable },
- { AL_EFFECT_FREQUENCY_SHIFTER, FshifterEffectProps, FshifterEffectVtable },
- { AL_EFFECT_RING_MODULATOR, ModulatorEffectProps, ModulatorEffectVtable },
- { AL_EFFECT_PITCH_SHIFTER, PshifterEffectProps, PshifterEffectVtable },
- { AL_EFFECT_VOCAL_MORPHER, VmorpherEffectProps, VmorpherEffectVtable },
- { AL_EFFECT_DEDICATED_DIALOGUE, DedicatedEffectProps, DedicatedEffectVtable },
- { AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT, DedicatedEffectProps, DedicatedEffectVtable },
- { AL_EFFECT_CONVOLUTION_SOFT, ConvolutionEffectProps, ConvolutionEffectVtable },
-};
-
-
-void ALeffect_setParami(ALeffect *effect, ALenum param, int value)
-{ effect->vtab->setParami(&effect->Props, param, value); }
-void ALeffect_setParamiv(ALeffect *effect, ALenum param, const int *values)
-{ effect->vtab->setParamiv(&effect->Props, param, values); }
-void ALeffect_setParamf(ALeffect *effect, ALenum param, float value)
-{ effect->vtab->setParamf(&effect->Props, param, value); }
-void ALeffect_setParamfv(ALeffect *effect, ALenum param, const float *values)
-{ effect->vtab->setParamfv(&effect->Props, param, values); }
+using SubListAllocator = typename al::allocator<std::array<ALeffect,64>>;
-void ALeffect_getParami(const ALeffect *effect, ALenum param, int *value)
-{ effect->vtab->getParami(&effect->Props, param, value); }
-void ALeffect_getParamiv(const ALeffect *effect, ALenum param, int *values)
-{ effect->vtab->getParamiv(&effect->Props, param, values); }
-void ALeffect_getParamf(const ALeffect *effect, ALenum param, float *value)
-{ effect->vtab->getParamf(&effect->Props, param, value); }
-void ALeffect_getParamfv(const ALeffect *effect, ALenum param, float *values)
-{ effect->vtab->getParamfv(&effect->Props, param, values); }
-
-
-const EffectPropsItem *getEffectPropsItemByType(ALenum type)
+auto GetDefaultProps(ALenum type) -> const EffectProps&
{
- auto iter = std::find_if(std::begin(EffectPropsList), std::end(EffectPropsList),
- [type](const EffectPropsItem &item) noexcept -> bool
- { return item.Type == type; });
- return (iter != std::end(EffectPropsList)) ? al::to_address(iter) : nullptr;
+ switch(type)
+ {
+ case AL_EFFECT_NULL: return NullEffectProps;
+ case AL_EFFECT_EAXREVERB: return ReverbEffectProps;
+ case AL_EFFECT_REVERB: return StdReverbEffectProps;
+ case AL_EFFECT_AUTOWAH: return AutowahEffectProps;
+ case AL_EFFECT_CHORUS: return ChorusEffectProps;
+ case AL_EFFECT_COMPRESSOR: return CompressorEffectProps;
+ case AL_EFFECT_DISTORTION: return DistortionEffectProps;
+ case AL_EFFECT_ECHO: return EchoEffectProps;
+ case AL_EFFECT_EQUALIZER: return EqualizerEffectProps;
+ case AL_EFFECT_FLANGER: return FlangerEffectProps;
+ case AL_EFFECT_FREQUENCY_SHIFTER: return FshifterEffectProps;
+ case AL_EFFECT_RING_MODULATOR: return ModulatorEffectProps;
+ case AL_EFFECT_PITCH_SHIFTER: return PshifterEffectProps;
+ case AL_EFFECT_VOCAL_MORPHER: return VmorpherEffectProps;
+ case AL_EFFECT_DEDICATED_DIALOGUE: return DedicatedDialogEffectProps;
+ case AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT: return DedicatedLfeEffectProps;
+ case AL_EFFECT_CONVOLUTION_SOFT: return ConvolutionEffectProps;
+ }
+ return NullEffectProps;
}
void InitEffectParams(ALeffect *effect, ALenum type)
{
- const EffectPropsItem *item{getEffectPropsItemByType(type)};
- if(item)
- {
- effect->Props = item->DefaultProps;
- effect->vtab = &item->Vtable;
- }
- else
- {
- effect->Props = EffectProps{};
- effect->vtab = &NullEffectVtable;
- }
+ effect->Props = GetDefaultProps(type);
effect->type = type;
}
@@ -166,21 +128,21 @@ bool EnsureEffects(ALCdevice *device, size_t needed)
[](size_t cur, const EffectSubList &sublist) noexcept -> size_t
{ return cur + static_cast<ALuint>(al::popcount(sublist.FreeMask)); })};
- while(needed > count)
- {
- if(device->EffectList.size() >= 1<<25) UNLIKELY
- return false;
-
- device->EffectList.emplace_back();
- auto sublist = device->EffectList.end() - 1;
- sublist->FreeMask = ~0_u64;
- sublist->Effects = static_cast<ALeffect*>(al_calloc(alignof(ALeffect), sizeof(ALeffect)*64));
- if(!sublist->Effects) UNLIKELY
+ try {
+ while(needed > count)
{
- device->EffectList.pop_back();
- return false;
+ if(device->EffectList.size() >= 1<<25) UNLIKELY
+ return false;
+
+ EffectSubList sublist{};
+ sublist.FreeMask = ~0_u64;
+ sublist.Effects = SubListAllocator{}.allocate(1);
+ device->EffectList.emplace_back(std::move(sublist));
+ count += 64;
}
- count += 64;
+ }
+ catch(...) {
+ return false;
}
return true;
}
@@ -194,7 +156,7 @@ ALeffect *AllocEffect(ALCdevice *device)
auto slidx = static_cast<ALuint>(al::countr_zero(sublist->FreeMask));
ASSUME(slidx < 64);
- ALeffect *effect{al::construct_at(sublist->Effects + slidx)};
+ ALeffect *effect{al::construct_at(al::to_address(sublist->Effects->begin() + slidx))};
InitEffectParams(effect, AL_EFFECT_NULL);
/* Add 1 to avoid effect ID 0. */
@@ -228,7 +190,7 @@ inline ALeffect *LookupEffect(ALCdevice *device, ALuint id)
EffectSubList &sublist = device->EffectList[lidx];
if(sublist.FreeMask & (1_u64 << slidx)) UNLIKELY
return nullptr;
- return sublist.Effects + slidx;
+ return al::to_address(sublist.Effects->begin() + slidx);
}
} // namespace
@@ -328,7 +290,7 @@ FORCE_ALIGN void AL_APIENTRY alEffectiDirect(ALCcontext *context, ALuint effect,
{
for(const EffectList &effectitem : gEffectList)
{
- if(value == effectitem.val && !DisabledEffects[effectitem.type])
+ if(value == effectitem.val && !DisabledEffects.test(effectitem.type))
{
isOk = true;
break;
@@ -344,7 +306,16 @@ FORCE_ALIGN void AL_APIENTRY alEffectiDirect(ALCcontext *context, ALuint effect,
else try
{
/* Call the appropriate handler */
- ALeffect_setParami(aleffect, param, value);
+ std::visit([aleffect,param,value](auto &arg)
+ {
+ using Type = std::remove_cv_t<std::remove_reference_t<decltype(arg)>>;
+ if constexpr(std::is_same_v<Type,ReverbProps>)
+ {
+ if(aleffect->type == AL_EFFECT_REVERB)
+ return EffectHandler::StdReverbSetParami(arg, param, value);
+ }
+ return EffectHandler::SetParami(arg, param, value);
+ }, aleffect->Props);
}
catch(effect_exception &e) {
context->setError(e.errorCode(), "%s", e.what());
@@ -371,7 +342,16 @@ FORCE_ALIGN void AL_APIENTRY alEffectivDirect(ALCcontext *context, ALuint effect
else try
{
/* Call the appropriate handler */
- ALeffect_setParamiv(aleffect, param, values);
+ std::visit([aleffect,param,values](auto &arg)
+ {
+ using Type = std::remove_cv_t<std::remove_reference_t<decltype(arg)>>;
+ if constexpr(std::is_same_v<Type,ReverbProps>)
+ {
+ if(aleffect->type == AL_EFFECT_REVERB)
+ return EffectHandler::StdReverbSetParamiv(arg, param, values);
+ }
+ return EffectHandler::SetParamiv(arg, param, values);
+ }, aleffect->Props);
}
catch(effect_exception &e) {
context->setError(e.errorCode(), "%s", e.what());
@@ -391,7 +371,16 @@ FORCE_ALIGN void AL_APIENTRY alEffectfDirect(ALCcontext *context, ALuint effect,
else try
{
/* Call the appropriate handler */
- ALeffect_setParamf(aleffect, param, value);
+ std::visit([aleffect,param,value](auto &arg)
+ {
+ using Type = std::remove_cv_t<std::remove_reference_t<decltype(arg)>>;
+ if constexpr(std::is_same_v<Type,ReverbProps>)
+ {
+ if(aleffect->type == AL_EFFECT_REVERB)
+ return EffectHandler::StdReverbSetParamf(arg, param, value);
+ }
+ return EffectHandler::SetParamf(arg, param, value);
+ }, aleffect->Props);
}
catch(effect_exception &e) {
context->setError(e.errorCode(), "%s", e.what());
@@ -411,7 +400,16 @@ FORCE_ALIGN void AL_APIENTRY alEffectfvDirect(ALCcontext *context, ALuint effect
else try
{
/* Call the appropriate handler */
- ALeffect_setParamfv(aleffect, param, values);
+ std::visit([aleffect,param,values](auto &arg)
+ {
+ using Type = std::remove_cv_t<std::remove_reference_t<decltype(arg)>>;
+ if constexpr(std::is_same_v<Type,ReverbProps>)
+ {
+ if(aleffect->type == AL_EFFECT_REVERB)
+ return EffectHandler::StdReverbSetParamfv(arg, param, values);
+ }
+ return EffectHandler::SetParamfv(arg, param, values);
+ }, aleffect->Props);
}
catch(effect_exception &e) {
context->setError(e.errorCode(), "%s", e.what());
@@ -433,7 +431,16 @@ FORCE_ALIGN void AL_APIENTRY alGetEffectiDirect(ALCcontext *context, ALuint effe
else try
{
/* Call the appropriate handler */
- ALeffect_getParami(aleffect, param, value);
+ std::visit([aleffect,param,value](auto &arg)
+ {
+ using Type = std::remove_cv_t<std::remove_reference_t<decltype(arg)>>;
+ if constexpr(std::is_same_v<Type,ReverbProps>)
+ {
+ if(aleffect->type == AL_EFFECT_REVERB)
+ return EffectHandler::StdReverbGetParami(arg, param, value);
+ }
+ return EffectHandler::GetParami(arg, param, value);
+ }, aleffect->Props);
}
catch(effect_exception &e) {
context->setError(e.errorCode(), "%s", e.what());
@@ -460,7 +467,16 @@ FORCE_ALIGN void AL_APIENTRY alGetEffectivDirect(ALCcontext *context, ALuint eff
else try
{
/* Call the appropriate handler */
- ALeffect_getParamiv(aleffect, param, values);
+ std::visit([aleffect,param,values](auto &arg)
+ {
+ using Type = std::remove_cv_t<std::remove_reference_t<decltype(arg)>>;
+ if constexpr(std::is_same_v<Type,ReverbProps>)
+ {
+ if(aleffect->type == AL_EFFECT_REVERB)
+ return EffectHandler::StdReverbGetParamiv(arg, param, values);
+ }
+ return EffectHandler::GetParamiv(arg, param, values);
+ }, aleffect->Props);
}
catch(effect_exception &e) {
context->setError(e.errorCode(), "%s", e.what());
@@ -480,7 +496,16 @@ FORCE_ALIGN void AL_APIENTRY alGetEffectfDirect(ALCcontext *context, ALuint effe
else try
{
/* Call the appropriate handler */
- ALeffect_getParamf(aleffect, param, value);
+ std::visit([aleffect,param,value](auto &arg)
+ {
+ using Type = std::remove_cv_t<std::remove_reference_t<decltype(arg)>>;
+ if constexpr(std::is_same_v<Type,ReverbProps>)
+ {
+ if(aleffect->type == AL_EFFECT_REVERB)
+ return EffectHandler::StdReverbGetParamf(arg, param, value);
+ }
+ return EffectHandler::GetParamf(arg, param, value);
+ }, aleffect->Props);
}
catch(effect_exception &e) {
context->setError(e.errorCode(), "%s", e.what());
@@ -500,7 +525,16 @@ FORCE_ALIGN void AL_APIENTRY alGetEffectfvDirect(ALCcontext *context, ALuint eff
else try
{
/* Call the appropriate handler */
- ALeffect_getParamfv(aleffect, param, values);
+ std::visit([aleffect,param,values](auto &arg)
+ {
+ using Type = std::remove_cv_t<std::remove_reference_t<decltype(arg)>>;
+ if constexpr(std::is_same_v<Type,ReverbProps>)
+ {
+ if(aleffect->type == AL_EFFECT_REVERB)
+ return EffectHandler::StdReverbGetParamfv(arg, param, values);
+ }
+ return EffectHandler::GetParamfv(arg, param, values);
+ }, aleffect->Props);
}
catch(effect_exception &e) {
context->setError(e.errorCode(), "%s", e.what());
@@ -535,20 +569,21 @@ EffectSubList::~EffectSubList()
while(usemask)
{
const int idx{al::countr_zero(usemask)};
- std::destroy_at(Effects+idx);
+ std::destroy_at(al::to_address(Effects->begin()+idx));
usemask &= ~(1_u64 << idx);
}
FreeMask = ~usemask;
- al_free(Effects);
+ SubListAllocator{}.deallocate(Effects, 1);
Effects = nullptr;
}
-#define DECL(x) { #x, EFX_REVERB_PRESET_##x }
-static const struct {
- const char name[32];
+struct EffectPreset {
+ const char name[32]; /* NOLINT(*-avoid-c-arrays) */
EFXEAXREVERBPROPERTIES props;
-} reverblist[] = {
+};
+#define DECL(x) EffectPreset{#x, EFX_REVERB_PRESET_##x}
+static constexpr std::array reverblist{
DECL(GENERIC),
DECL(PADDEDCELL),
DECL(ROOM),
@@ -687,48 +722,47 @@ void LoadReverbPreset(const char *name, ALeffect *effect)
return;
}
- if(!DisabledEffects[EAXREVERB_EFFECT])
+ if(!DisabledEffects.test(EAXREVERB_EFFECT))
InitEffectParams(effect, AL_EFFECT_EAXREVERB);
- else if(!DisabledEffects[REVERB_EFFECT])
+ else if(!DisabledEffects.test(REVERB_EFFECT))
InitEffectParams(effect, AL_EFFECT_REVERB);
else
InitEffectParams(effect, AL_EFFECT_NULL);
for(const auto &reverbitem : reverblist)
{
- const EFXEAXREVERBPROPERTIES *props;
-
if(al::strcasecmp(name, reverbitem.name) != 0)
continue;
TRACE("Loading reverb '%s'\n", reverbitem.name);
- props = &reverbitem.props;
- effect->Props.Reverb.Density = props->flDensity;
- effect->Props.Reverb.Diffusion = props->flDiffusion;
- effect->Props.Reverb.Gain = props->flGain;
- effect->Props.Reverb.GainHF = props->flGainHF;
- effect->Props.Reverb.GainLF = props->flGainLF;
- effect->Props.Reverb.DecayTime = props->flDecayTime;
- effect->Props.Reverb.DecayHFRatio = props->flDecayHFRatio;
- effect->Props.Reverb.DecayLFRatio = props->flDecayLFRatio;
- effect->Props.Reverb.ReflectionsGain = props->flReflectionsGain;
- effect->Props.Reverb.ReflectionsDelay = props->flReflectionsDelay;
- effect->Props.Reverb.ReflectionsPan[0] = props->flReflectionsPan[0];
- effect->Props.Reverb.ReflectionsPan[1] = props->flReflectionsPan[1];
- effect->Props.Reverb.ReflectionsPan[2] = props->flReflectionsPan[2];
- effect->Props.Reverb.LateReverbGain = props->flLateReverbGain;
- effect->Props.Reverb.LateReverbDelay = props->flLateReverbDelay;
- effect->Props.Reverb.LateReverbPan[0] = props->flLateReverbPan[0];
- effect->Props.Reverb.LateReverbPan[1] = props->flLateReverbPan[1];
- effect->Props.Reverb.LateReverbPan[2] = props->flLateReverbPan[2];
- effect->Props.Reverb.EchoTime = props->flEchoTime;
- effect->Props.Reverb.EchoDepth = props->flEchoDepth;
- effect->Props.Reverb.ModulationTime = props->flModulationTime;
- effect->Props.Reverb.ModulationDepth = props->flModulationDepth;
- effect->Props.Reverb.AirAbsorptionGainHF = props->flAirAbsorptionGainHF;
- effect->Props.Reverb.HFReference = props->flHFReference;
- effect->Props.Reverb.LFReference = props->flLFReference;
- effect->Props.Reverb.RoomRolloffFactor = props->flRoomRolloffFactor;
- effect->Props.Reverb.DecayHFLimit = props->iDecayHFLimit ? AL_TRUE : AL_FALSE;
+ const auto &props = reverbitem.props;
+ auto &dst = std::get<ReverbProps>(effect->Props);
+ dst.Density = props.flDensity;
+ dst.Diffusion = props.flDiffusion;
+ dst.Gain = props.flGain;
+ dst.GainHF = props.flGainHF;
+ dst.GainLF = props.flGainLF;
+ dst.DecayTime = props.flDecayTime;
+ dst.DecayHFRatio = props.flDecayHFRatio;
+ dst.DecayLFRatio = props.flDecayLFRatio;
+ dst.ReflectionsGain = props.flReflectionsGain;
+ dst.ReflectionsDelay = props.flReflectionsDelay;
+ dst.ReflectionsPan[0] = props.flReflectionsPan[0];
+ dst.ReflectionsPan[1] = props.flReflectionsPan[1];
+ dst.ReflectionsPan[2] = props.flReflectionsPan[2];
+ dst.LateReverbGain = props.flLateReverbGain;
+ dst.LateReverbDelay = props.flLateReverbDelay;
+ dst.LateReverbPan[0] = props.flLateReverbPan[0];
+ dst.LateReverbPan[1] = props.flLateReverbPan[1];
+ dst.LateReverbPan[2] = props.flLateReverbPan[2];
+ dst.EchoTime = props.flEchoTime;
+ dst.EchoDepth = props.flEchoDepth;
+ dst.ModulationTime = props.flModulationTime;
+ dst.ModulationDepth = props.flModulationDepth;
+ dst.AirAbsorptionGainHF = props.flAirAbsorptionGainHF;
+ dst.HFReference = props.flHFReference;
+ dst.LFReference = props.flLFReference;
+ dst.RoomRolloffFactor = props.flRoomRolloffFactor;
+ dst.DecayHFLimit = props.iDecayHFLimit ? AL_TRUE : AL_FALSE;
return;
}
@@ -742,7 +776,7 @@ bool IsValidEffectType(ALenum type) noexcept
for(const auto &effect_item : gEffectList)
{
- if(type == effect_item.val && !DisabledEffects[effect_item.type])
+ if(type == effect_item.val && !DisabledEffects.test(effect_item.type))
return true;
}
return false;
diff --git a/al/effect.h b/al/effect.h
index 27e9dd72..8f069bee 100644
--- a/al/effect.h
+++ b/al/effect.h
@@ -1,6 +1,9 @@
#ifndef AL_EFFECT_H
#define AL_EFFECT_H
+#include <array>
+#include <bitset>
+#include <cstdint>
#include <string_view>
#include "AL/al.h"
@@ -8,6 +11,8 @@
#include "al/effects/effects.h"
#include "alc/effects/base.h"
+#include "almalloc.h"
+#include "alnumeric.h"
enum {
@@ -29,16 +34,14 @@ enum {
MAX_EFFECTS
};
-extern bool DisabledEffects[MAX_EFFECTS];
-
-extern float ReverbBoost;
+inline std::bitset<MAX_EFFECTS> DisabledEffects;
struct EffectList {
- const char name[16];
- int type;
+ const char name[16]; /* NOLINT(*-avoid-c-arrays) */
+ ALuint type;
ALenum val;
};
-extern const EffectList gEffectList[16];
+extern const std::array<EffectList,16> gEffectList;
struct ALeffect {
@@ -47,14 +50,12 @@ struct ALeffect {
EffectProps Props{};
- const EffectVtable *vtab{nullptr};
-
/* Self ID */
ALuint id{0u};
static void SetName(ALCcontext *context, ALuint id, std::string_view name);
- DISABLE_ALLOC()
+ DISABLE_ALLOC
};
void InitEffect(ALeffect *effect);
@@ -63,4 +64,19 @@ void LoadReverbPreset(const char *name, ALeffect *effect);
bool IsValidEffectType(ALenum type) noexcept;
+struct EffectSubList {
+ uint64_t FreeMask{~0_u64};
+ gsl::owner<std::array<ALeffect,64>*> 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; }
+};
+
#endif
diff --git a/al/effects/autowah.cpp b/al/effects/autowah.cpp
index 1a8b43fc..68704c11 100644
--- a/al/effects/autowah.cpp
+++ b/al/effects/autowah.cpp
@@ -20,100 +20,87 @@
namespace {
-void Autowah_setParamf(EffectProps *props, ALenum param, float val)
+EffectProps genDefaultProps() noexcept
+{
+ AutowahProps props{};
+ props.AttackTime = AL_AUTOWAH_DEFAULT_ATTACK_TIME;
+ props.ReleaseTime = AL_AUTOWAH_DEFAULT_RELEASE_TIME;
+ props.Resonance = AL_AUTOWAH_DEFAULT_RESONANCE;
+ props.PeakGain = AL_AUTOWAH_DEFAULT_PEAK_GAIN;
+ return props;
+}
+
+} // namespace
+
+const EffectProps AutowahEffectProps{genDefaultProps()};
+
+void EffectHandler::SetParami(AutowahProps&, ALenum param, int)
+{ throw effect_exception{AL_INVALID_ENUM, "Invalid autowah integer property 0x%04x", param}; }
+void EffectHandler::SetParamiv(AutowahProps&, ALenum param, const int*)
+{
+ throw effect_exception{AL_INVALID_ENUM, "Invalid autowah integer vector property 0x%04x",
+ param};
+}
+
+void EffectHandler::SetParamf(AutowahProps &props, ALenum param, float val)
{
switch(param)
{
case AL_AUTOWAH_ATTACK_TIME:
if(!(val >= AL_AUTOWAH_MIN_ATTACK_TIME && val <= AL_AUTOWAH_MAX_ATTACK_TIME))
throw effect_exception{AL_INVALID_VALUE, "Autowah attack time out of range"};
- props->Autowah.AttackTime = val;
+ props.AttackTime = val;
break;
case AL_AUTOWAH_RELEASE_TIME:
if(!(val >= AL_AUTOWAH_MIN_RELEASE_TIME && val <= AL_AUTOWAH_MAX_RELEASE_TIME))
throw effect_exception{AL_INVALID_VALUE, "Autowah release time out of range"};
- props->Autowah.ReleaseTime = val;
+ props.ReleaseTime = val;
break;
case AL_AUTOWAH_RESONANCE:
if(!(val >= AL_AUTOWAH_MIN_RESONANCE && val <= AL_AUTOWAH_MAX_RESONANCE))
throw effect_exception{AL_INVALID_VALUE, "Autowah resonance out of range"};
- props->Autowah.Resonance = val;
+ props.Resonance = val;
break;
case AL_AUTOWAH_PEAK_GAIN:
if(!(val >= AL_AUTOWAH_MIN_PEAK_GAIN && val <= AL_AUTOWAH_MAX_PEAK_GAIN))
throw effect_exception{AL_INVALID_VALUE, "Autowah peak gain out of range"};
- props->Autowah.PeakGain = val;
+ props.PeakGain = val;
break;
default:
throw effect_exception{AL_INVALID_ENUM, "Invalid autowah float property 0x%04x", param};
}
}
-void Autowah_setParamfv(EffectProps *props, ALenum param, const float *vals)
-{ Autowah_setParamf(props, param, vals[0]); }
+void EffectHandler::SetParamfv(AutowahProps &props, ALenum param, const float *vals)
+{ SetParamf(props, param, vals[0]); }
-void Autowah_setParami(EffectProps*, ALenum param, int)
+void EffectHandler::GetParami(const AutowahProps&, ALenum param, int*)
{ throw effect_exception{AL_INVALID_ENUM, "Invalid autowah integer property 0x%04x", param}; }
-void Autowah_setParamiv(EffectProps*, ALenum param, const int*)
+void EffectHandler::GetParamiv(const AutowahProps&, ALenum param, int*)
{
throw effect_exception{AL_INVALID_ENUM, "Invalid autowah integer vector property 0x%04x",
param};
}
-void Autowah_getParamf(const EffectProps *props, ALenum param, float *val)
+void EffectHandler::GetParamf(const AutowahProps &props, ALenum param, float *val)
{
switch(param)
{
- case AL_AUTOWAH_ATTACK_TIME:
- *val = props->Autowah.AttackTime;
- break;
-
- case AL_AUTOWAH_RELEASE_TIME:
- *val = props->Autowah.ReleaseTime;
- break;
-
- case AL_AUTOWAH_RESONANCE:
- *val = props->Autowah.Resonance;
- break;
-
- case AL_AUTOWAH_PEAK_GAIN:
- *val = props->Autowah.PeakGain;
- break;
+ case AL_AUTOWAH_ATTACK_TIME: *val = props.AttackTime; break;
+ case AL_AUTOWAH_RELEASE_TIME: *val = props.ReleaseTime; break;
+ case AL_AUTOWAH_RESONANCE: *val = props.Resonance; break;
+ case AL_AUTOWAH_PEAK_GAIN: *val = props.PeakGain; break;
default:
throw effect_exception{AL_INVALID_ENUM, "Invalid autowah float property 0x%04x", param};
}
}
-void Autowah_getParamfv(const EffectProps *props, ALenum param, float *vals)
-{ Autowah_getParamf(props, param, vals); }
-
-void Autowah_getParami(const EffectProps*, ALenum param, int*)
-{ throw effect_exception{AL_INVALID_ENUM, "Invalid autowah integer property 0x%04x", param}; }
-void Autowah_getParamiv(const EffectProps*, ALenum param, int*)
-{
- throw effect_exception{AL_INVALID_ENUM, "Invalid autowah integer vector property 0x%04x",
- param};
-}
-
-EffectProps genDefaultProps() noexcept
-{
- EffectProps props{};
- props.Autowah.AttackTime = AL_AUTOWAH_DEFAULT_ATTACK_TIME;
- props.Autowah.ReleaseTime = AL_AUTOWAH_DEFAULT_RELEASE_TIME;
- props.Autowah.Resonance = AL_AUTOWAH_DEFAULT_RESONANCE;
- props.Autowah.PeakGain = AL_AUTOWAH_DEFAULT_PEAK_GAIN;
- return props;
-}
-
-} // namespace
-
-DEFINE_ALEFFECT_VTABLE(Autowah);
-
-const EffectProps AutowahEffectProps{genDefaultProps()};
+void EffectHandler::GetParamfv(const AutowahProps &props, ALenum param, float *vals)
+{ GetParamf(props, param, vals); }
#ifdef ALSOFT_EAX
namespace {
@@ -189,25 +176,25 @@ template<>
throw Exception{message};
}
-template<>
-bool AutowahCommitter::commit(const EaxEffectProps &props)
+bool EaxAutowahCommitter::commit(const EAXAUTOWAHPROPERTIES &props)
{
- if(props == mEaxProps)
+ if(auto *cur = std::get_if<EAXAUTOWAHPROPERTIES>(&mEaxProps); cur && *cur == props)
return false;
mEaxProps = props;
-
- auto &eaxprops = std::get<EAXAUTOWAHPROPERTIES>(props);
- mAlProps.Autowah.AttackTime = eaxprops.flAttackTime;
- mAlProps.Autowah.ReleaseTime = eaxprops.flReleaseTime;
- mAlProps.Autowah.Resonance = level_mb_to_gain(static_cast<float>(eaxprops.lResonance));
- mAlProps.Autowah.PeakGain = level_mb_to_gain(static_cast<float>(eaxprops.lPeakLevel));
+ mAlProps = [&]{
+ AutowahProps ret{};
+ ret.AttackTime = props.flAttackTime;
+ ret.ReleaseTime = props.flReleaseTime;
+ ret.Resonance = level_mb_to_gain(static_cast<float>(props.lResonance));
+ ret.PeakGain = level_mb_to_gain(static_cast<float>(props.lPeakLevel));
+ return ret;
+ }();
return true;
}
-template<>
-void AutowahCommitter::SetDefaults(EaxEffectProps &props)
+void EaxAutowahCommitter::SetDefaults(EaxEffectProps &props)
{
static constexpr EAXAUTOWAHPROPERTIES defprops{[]
{
@@ -221,10 +208,8 @@ void AutowahCommitter::SetDefaults(EaxEffectProps &props)
props = defprops;
}
-template<>
-void AutowahCommitter::Get(const EaxCall &call, const EaxEffectProps &props_)
+void EaxAutowahCommitter::Get(const EaxCall &call, const EAXAUTOWAHPROPERTIES &props)
{
- auto &props = std::get<EAXAUTOWAHPROPERTIES>(props_);
switch(call.get_property_id())
{
case EAXAUTOWAH_NONE: break;
@@ -237,10 +222,8 @@ void AutowahCommitter::Get(const EaxCall &call, const EaxEffectProps &props_)
}
}
-template<>
-void AutowahCommitter::Set(const EaxCall &call, EaxEffectProps &props_)
+void EaxAutowahCommitter::Set(const EaxCall &call, EAXAUTOWAHPROPERTIES &props)
{
- auto &props = std::get<EAXAUTOWAHPROPERTIES>(props_);
switch(call.get_property_id())
{
case EAXAUTOWAH_NONE: break;
diff --git a/al/effects/chorus.cpp b/al/effects/chorus.cpp
index 90b38e4d..913d1215 100644
--- a/al/effects/chorus.cpp
+++ b/al/effects/chorus.cpp
@@ -46,13 +46,41 @@ inline ALenum EnumFromWaveform(ChorusWaveform type)
throw std::runtime_error{"Invalid chorus waveform: "+std::to_string(static_cast<int>(type))};
}
-void Chorus_setParami(EffectProps *props, ALenum param, int val)
+EffectProps genDefaultChorusProps() noexcept
+{
+ ChorusProps props{};
+ props.Waveform = WaveformFromEnum(AL_CHORUS_DEFAULT_WAVEFORM).value();
+ props.Phase = AL_CHORUS_DEFAULT_PHASE;
+ props.Rate = AL_CHORUS_DEFAULT_RATE;
+ props.Depth = AL_CHORUS_DEFAULT_DEPTH;
+ props.Feedback = AL_CHORUS_DEFAULT_FEEDBACK;
+ props.Delay = AL_CHORUS_DEFAULT_DELAY;
+ return props;
+}
+
+EffectProps genDefaultFlangerProps() noexcept
+{
+ FlangerProps props{};
+ props.Waveform = WaveformFromEnum(AL_FLANGER_DEFAULT_WAVEFORM).value();
+ props.Phase = AL_FLANGER_DEFAULT_PHASE;
+ props.Rate = AL_FLANGER_DEFAULT_RATE;
+ props.Depth = AL_FLANGER_DEFAULT_DEPTH;
+ props.Feedback = AL_FLANGER_DEFAULT_FEEDBACK;
+ props.Delay = AL_FLANGER_DEFAULT_DELAY;
+ return props;
+}
+
+} // namespace
+
+const EffectProps ChorusEffectProps{genDefaultChorusProps()};
+
+void EffectHandler::SetParami(ChorusProps &props, ALenum param, int val)
{
switch(param)
{
case AL_CHORUS_WAVEFORM:
if(auto formopt = WaveformFromEnum(val))
- props->Chorus.Waveform = *formopt;
+ props.Waveform = *formopt;
else
throw effect_exception{AL_INVALID_VALUE, "Invalid chorus waveform: 0x%04x", val};
break;
@@ -60,115 +88,89 @@ void Chorus_setParami(EffectProps *props, ALenum param, int val)
case AL_CHORUS_PHASE:
if(!(val >= AL_CHORUS_MIN_PHASE && val <= AL_CHORUS_MAX_PHASE))
throw effect_exception{AL_INVALID_VALUE, "Chorus phase out of range: %d", val};
- props->Chorus.Phase = val;
+ props.Phase = val;
break;
default:
throw effect_exception{AL_INVALID_ENUM, "Invalid chorus integer property 0x%04x", param};
}
}
-void Chorus_setParamiv(EffectProps *props, ALenum param, const int *vals)
-{ Chorus_setParami(props, param, vals[0]); }
-void Chorus_setParamf(EffectProps *props, ALenum param, float val)
+void EffectHandler::SetParamiv(ChorusProps &props, ALenum param, const int *vals)
+{ SetParami(props, param, vals[0]); }
+void EffectHandler::SetParamf(ChorusProps &props, ALenum param, float val)
{
switch(param)
{
case AL_CHORUS_RATE:
if(!(val >= AL_CHORUS_MIN_RATE && val <= AL_CHORUS_MAX_RATE))
throw effect_exception{AL_INVALID_VALUE, "Chorus rate out of range: %f", val};
- props->Chorus.Rate = val;
+ props.Rate = val;
break;
case AL_CHORUS_DEPTH:
if(!(val >= AL_CHORUS_MIN_DEPTH && val <= AL_CHORUS_MAX_DEPTH))
throw effect_exception{AL_INVALID_VALUE, "Chorus depth out of range: %f", val};
- props->Chorus.Depth = val;
+ props.Depth = val;
break;
case AL_CHORUS_FEEDBACK:
if(!(val >= AL_CHORUS_MIN_FEEDBACK && val <= AL_CHORUS_MAX_FEEDBACK))
throw effect_exception{AL_INVALID_VALUE, "Chorus feedback out of range: %f", val};
- props->Chorus.Feedback = val;
+ props.Feedback = val;
break;
case AL_CHORUS_DELAY:
if(!(val >= AL_CHORUS_MIN_DELAY && val <= AL_CHORUS_MAX_DELAY))
throw effect_exception{AL_INVALID_VALUE, "Chorus delay out of range: %f", val};
- props->Chorus.Delay = val;
+ props.Delay = val;
break;
default:
throw effect_exception{AL_INVALID_ENUM, "Invalid chorus float property 0x%04x", param};
}
}
-void Chorus_setParamfv(EffectProps *props, ALenum param, const float *vals)
-{ Chorus_setParamf(props, param, vals[0]); }
+void EffectHandler::SetParamfv(ChorusProps &props, ALenum param, const float *vals)
+{ SetParamf(props, param, vals[0]); }
-void Chorus_getParami(const EffectProps *props, ALenum param, int *val)
+void EffectHandler::GetParami(const ChorusProps &props, ALenum param, int *val)
{
switch(param)
{
- case AL_CHORUS_WAVEFORM:
- *val = EnumFromWaveform(props->Chorus.Waveform);
- break;
-
- case AL_CHORUS_PHASE:
- *val = props->Chorus.Phase;
- break;
+ case AL_CHORUS_WAVEFORM: *val = EnumFromWaveform(props.Waveform); break;
+ case AL_CHORUS_PHASE: *val = props.Phase; break;
default:
throw effect_exception{AL_INVALID_ENUM, "Invalid chorus integer property 0x%04x", param};
}
}
-void Chorus_getParamiv(const EffectProps *props, ALenum param, int *vals)
-{ Chorus_getParami(props, param, vals); }
-void Chorus_getParamf(const EffectProps *props, ALenum param, float *val)
+void EffectHandler::GetParamiv(const ChorusProps &props, ALenum param, int *vals)
+{ GetParami(props, param, vals); }
+void EffectHandler::GetParamf(const ChorusProps &props, ALenum param, float *val)
{
switch(param)
{
- case AL_CHORUS_RATE:
- *val = props->Chorus.Rate;
- break;
-
- case AL_CHORUS_DEPTH:
- *val = props->Chorus.Depth;
- break;
-
- case AL_CHORUS_FEEDBACK:
- *val = props->Chorus.Feedback;
- break;
-
- case AL_CHORUS_DELAY:
- *val = props->Chorus.Delay;
- break;
+ case AL_CHORUS_RATE: *val = props.Rate; break;
+ case AL_CHORUS_DEPTH: *val = props.Depth; break;
+ case AL_CHORUS_FEEDBACK: *val = props.Feedback; break;
+ case AL_CHORUS_DELAY: *val = props.Delay; break;
default:
throw effect_exception{AL_INVALID_ENUM, "Invalid chorus float property 0x%04x", param};
}
}
-void Chorus_getParamfv(const EffectProps *props, ALenum param, float *vals)
-{ Chorus_getParamf(props, param, vals); }
+void EffectHandler::GetParamfv(const ChorusProps &props, ALenum param, float *vals)
+{ GetParamf(props, param, vals); }
-EffectProps genDefaultChorusProps() noexcept
-{
- EffectProps props{};
- props.Chorus.Waveform = *WaveformFromEnum(AL_CHORUS_DEFAULT_WAVEFORM);
- props.Chorus.Phase = AL_CHORUS_DEFAULT_PHASE;
- props.Chorus.Rate = AL_CHORUS_DEFAULT_RATE;
- props.Chorus.Depth = AL_CHORUS_DEFAULT_DEPTH;
- props.Chorus.Feedback = AL_CHORUS_DEFAULT_FEEDBACK;
- props.Chorus.Delay = AL_CHORUS_DEFAULT_DELAY;
- return props;
-}
+const EffectProps FlangerEffectProps{genDefaultFlangerProps()};
-void Flanger_setParami(EffectProps *props, ALenum param, int val)
+void EffectHandler::SetParami(FlangerProps &props, ALenum param, int val)
{
switch(param)
{
case AL_FLANGER_WAVEFORM:
if(auto formopt = WaveformFromEnum(val))
- props->Chorus.Waveform = *formopt;
+ props.Waveform = *formopt;
else
throw effect_exception{AL_INVALID_VALUE, "Invalid flanger waveform: 0x%04x", val};
break;
@@ -176,124 +178,87 @@ void Flanger_setParami(EffectProps *props, ALenum param, int val)
case AL_FLANGER_PHASE:
if(!(val >= AL_FLANGER_MIN_PHASE && val <= AL_FLANGER_MAX_PHASE))
throw effect_exception{AL_INVALID_VALUE, "Flanger phase out of range: %d", val};
- props->Chorus.Phase = val;
+ props.Phase = val;
break;
default:
throw effect_exception{AL_INVALID_ENUM, "Invalid flanger integer property 0x%04x", param};
}
}
-void Flanger_setParamiv(EffectProps *props, ALenum param, const int *vals)
-{ Flanger_setParami(props, param, vals[0]); }
-void Flanger_setParamf(EffectProps *props, ALenum param, float val)
+void EffectHandler::SetParamiv(FlangerProps &props, ALenum param, const int *vals)
+{ SetParami(props, param, vals[0]); }
+void EffectHandler::SetParamf(FlangerProps &props, ALenum param, float val)
{
switch(param)
{
case AL_FLANGER_RATE:
if(!(val >= AL_FLANGER_MIN_RATE && val <= AL_FLANGER_MAX_RATE))
throw effect_exception{AL_INVALID_VALUE, "Flanger rate out of range: %f", val};
- props->Chorus.Rate = val;
+ props.Rate = val;
break;
case AL_FLANGER_DEPTH:
if(!(val >= AL_FLANGER_MIN_DEPTH && val <= AL_FLANGER_MAX_DEPTH))
throw effect_exception{AL_INVALID_VALUE, "Flanger depth out of range: %f", val};
- props->Chorus.Depth = val;
+ props.Depth = val;
break;
case AL_FLANGER_FEEDBACK:
if(!(val >= AL_FLANGER_MIN_FEEDBACK && val <= AL_FLANGER_MAX_FEEDBACK))
throw effect_exception{AL_INVALID_VALUE, "Flanger feedback out of range: %f", val};
- props->Chorus.Feedback = val;
+ props.Feedback = val;
break;
case AL_FLANGER_DELAY:
if(!(val >= AL_FLANGER_MIN_DELAY && val <= AL_FLANGER_MAX_DELAY))
throw effect_exception{AL_INVALID_VALUE, "Flanger delay out of range: %f", val};
- props->Chorus.Delay = val;
+ props.Delay = val;
break;
default:
throw effect_exception{AL_INVALID_ENUM, "Invalid flanger float property 0x%04x", param};
}
}
-void Flanger_setParamfv(EffectProps *props, ALenum param, const float *vals)
-{ Flanger_setParamf(props, param, vals[0]); }
+void EffectHandler::SetParamfv(FlangerProps &props, ALenum param, const float *vals)
+{ SetParamf(props, param, vals[0]); }
-void Flanger_getParami(const EffectProps *props, ALenum param, int *val)
+void EffectHandler::GetParami(const FlangerProps &props, ALenum param, int *val)
{
switch(param)
{
- case AL_FLANGER_WAVEFORM:
- *val = EnumFromWaveform(props->Chorus.Waveform);
- break;
-
- case AL_FLANGER_PHASE:
- *val = props->Chorus.Phase;
- break;
+ case AL_FLANGER_WAVEFORM: *val = EnumFromWaveform(props.Waveform); break;
+ case AL_FLANGER_PHASE: *val = props.Phase; break;
default:
throw effect_exception{AL_INVALID_ENUM, "Invalid flanger integer property 0x%04x", param};
}
}
-void Flanger_getParamiv(const EffectProps *props, ALenum param, int *vals)
-{ Flanger_getParami(props, param, vals); }
-void Flanger_getParamf(const EffectProps *props, ALenum param, float *val)
+void EffectHandler::GetParamiv(const FlangerProps &props, ALenum param, int *vals)
+{ GetParami(props, param, vals); }
+void EffectHandler::GetParamf(const FlangerProps &props, ALenum param, float *val)
{
switch(param)
{
- case AL_FLANGER_RATE:
- *val = props->Chorus.Rate;
- break;
-
- case AL_FLANGER_DEPTH:
- *val = props->Chorus.Depth;
- break;
-
- case AL_FLANGER_FEEDBACK:
- *val = props->Chorus.Feedback;
- break;
-
- case AL_FLANGER_DELAY:
- *val = props->Chorus.Delay;
- break;
+ case AL_FLANGER_RATE: *val = props.Rate; break;
+ case AL_FLANGER_DEPTH: *val = props.Depth; break;
+ case AL_FLANGER_FEEDBACK: *val = props.Feedback; break;
+ case AL_FLANGER_DELAY: *val = props.Delay; break;
default:
throw effect_exception{AL_INVALID_ENUM, "Invalid flanger float property 0x%04x", param};
}
}
-void Flanger_getParamfv(const EffectProps *props, ALenum param, float *vals)
-{ Flanger_getParamf(props, param, vals); }
-
-EffectProps genDefaultFlangerProps() noexcept
-{
- EffectProps props{};
- props.Chorus.Waveform = *WaveformFromEnum(AL_FLANGER_DEFAULT_WAVEFORM);
- props.Chorus.Phase = AL_FLANGER_DEFAULT_PHASE;
- props.Chorus.Rate = AL_FLANGER_DEFAULT_RATE;
- props.Chorus.Depth = AL_FLANGER_DEFAULT_DEPTH;
- props.Chorus.Feedback = AL_FLANGER_DEFAULT_FEEDBACK;
- props.Chorus.Delay = AL_FLANGER_DEFAULT_DELAY;
- return props;
-}
-
-} // namespace
-
-DEFINE_ALEFFECT_VTABLE(Chorus);
-
-const EffectProps ChorusEffectProps{genDefaultChorusProps()};
-
-DEFINE_ALEFFECT_VTABLE(Flanger);
-
-const EffectProps FlangerEffectProps{genDefaultFlangerProps()};
+void EffectHandler::GetParamfv(const FlangerProps &props, ALenum param, float *vals)
+{ GetParamf(props, param, vals); }
#ifdef ALSOFT_EAX
namespace {
struct EaxChorusTraits {
- using Props = EAXCHORUSPROPERTIES;
+ using EaxProps = EAXCHORUSPROPERTIES;
using Committer = EaxChorusCommitter;
+ using AlProps = ChorusProps;
static constexpr auto efx_effect() { return AL_EFFECT_CHORUS; }
@@ -357,8 +322,9 @@ struct EaxChorusTraits {
}; // EaxChorusTraits
struct EaxFlangerTraits {
- using Props = EAXFLANGERPROPERTIES;
+ using EaxProps = EAXFLANGERPROPERTIES;
using Committer = EaxFlangerCommitter;
+ using AlProps = FlangerProps;
static constexpr auto efx_effect() { return AL_EFFECT_FLANGER; }
@@ -424,7 +390,9 @@ struct EaxFlangerTraits {
template<typename TTraits>
struct ChorusFlangerEffect {
using Traits = TTraits;
+ using EaxProps = typename Traits::EaxProps;
using Committer = typename Traits::Committer;
+ using AlProps = typename Traits::AlProps;
using Exception = typename Committer::Exception;
struct WaveformValidator {
@@ -494,7 +462,7 @@ struct ChorusFlangerEffect {
}; // DelayValidator
struct AllValidator {
- void operator()(const typename Traits::Props& all) const
+ void operator()(const EaxProps& all) const
{
WaveformValidator{}(all.ulWaveform);
PhaseValidator{}(all.lPhase);
@@ -508,7 +476,7 @@ struct ChorusFlangerEffect {
public:
static void SetDefaults(EaxEffectProps &props)
{
- auto&& all = props.emplace<typename Traits::Props>();
+ auto&& all = props.emplace<EaxProps>();
all.ulWaveform = Traits::eax_default_waveform();
all.lPhase = Traits::eax_default_phase();
all.flRate = Traits::eax_default_rate();
@@ -518,102 +486,83 @@ public:
}
- static void Get(const EaxCall &call, const EaxEffectProps &props)
+ static void Get(const EaxCall &call, const EaxProps &all)
{
- auto&& all = std::get<typename Traits::Props>(props);
switch(call.get_property_id())
{
case Traits::eax_none_param_id():
break;
-
case Traits::eax_allparameters_param_id():
call.template set_value<Exception>(all);
break;
-
case Traits::eax_waveform_param_id():
call.template set_value<Exception>(all.ulWaveform);
break;
-
case Traits::eax_phase_param_id():
call.template set_value<Exception>(all.lPhase);
break;
-
case Traits::eax_rate_param_id():
call.template set_value<Exception>(all.flRate);
break;
-
case Traits::eax_depth_param_id():
call.template set_value<Exception>(all.flDepth);
break;
-
case Traits::eax_feedback_param_id():
call.template set_value<Exception>(all.flFeedback);
break;
-
case Traits::eax_delay_param_id():
call.template set_value<Exception>(all.flDelay);
break;
-
default:
Committer::fail_unknown_property_id();
}
}
- static void Set(const EaxCall &call, EaxEffectProps &props)
+ static void Set(const EaxCall &call, EaxProps &all)
{
- auto&& all = std::get<typename Traits::Props>(props);
switch(call.get_property_id())
{
case Traits::eax_none_param_id():
break;
-
case Traits::eax_allparameters_param_id():
Committer::template defer<AllValidator>(call, all);
break;
-
case Traits::eax_waveform_param_id():
Committer::template defer<WaveformValidator>(call, all.ulWaveform);
break;
-
case Traits::eax_phase_param_id():
Committer::template defer<PhaseValidator>(call, all.lPhase);
break;
-
case Traits::eax_rate_param_id():
Committer::template defer<RateValidator>(call, all.flRate);
break;
-
case Traits::eax_depth_param_id():
Committer::template defer<DepthValidator>(call, all.flDepth);
break;
-
case Traits::eax_feedback_param_id():
Committer::template defer<FeedbackValidator>(call, all.flFeedback);
break;
-
case Traits::eax_delay_param_id():
Committer::template defer<DelayValidator>(call, all.flDelay);
break;
-
default:
Committer::fail_unknown_property_id();
}
}
- static bool Commit(const EaxEffectProps &props, EaxEffectProps &props_, EffectProps &al_props_)
+ static bool Commit(const EaxProps &props, EaxEffectProps &props_, AlProps &al_props_)
{
- if(props == props_)
+ if(auto *cur = std::get_if<EaxProps>(&props_); cur && *cur == props)
return false;
props_ = props;
- auto&& dst = std::get<typename Traits::Props>(props);
- al_props_.Chorus.Waveform = Traits::eax_waveform(dst.ulWaveform);
- al_props_.Chorus.Phase = static_cast<int>(dst.lPhase);
- al_props_.Chorus.Rate = dst.flRate;
- al_props_.Chorus.Depth = dst.flDepth;
- al_props_.Chorus.Feedback = dst.flFeedback;
- al_props_.Chorus.Delay = dst.flDelay;
+ al_props_.Waveform = Traits::eax_waveform(props.ulWaveform);
+ al_props_.Phase = static_cast<int>(props.lPhase);
+ al_props_.Rate = props.flRate;
+ al_props_.Depth = props.flDepth;
+ al_props_.Feedback = props.flFeedback;
+ al_props_.Delay = props.flDelay;
return true;
}
@@ -638,29 +587,25 @@ template<>
throw Exception{message};
}
-template<>
-bool ChorusCommitter::commit(const EaxEffectProps &props)
+bool EaxChorusCommitter::commit(const EAXCHORUSPROPERTIES &props)
{
using Committer = ChorusFlangerEffect<EaxChorusTraits>;
- return Committer::Commit(props, mEaxProps, mAlProps);
+ return Committer::Commit(props, mEaxProps, mAlProps.emplace<ChorusProps>());
}
-template<>
-void ChorusCommitter::SetDefaults(EaxEffectProps &props)
+void EaxChorusCommitter::SetDefaults(EaxEffectProps &props)
{
using Committer = ChorusFlangerEffect<EaxChorusTraits>;
Committer::SetDefaults(props);
}
-template<>
-void ChorusCommitter::Get(const EaxCall &call, const EaxEffectProps &props)
+void EaxChorusCommitter::Get(const EaxCall &call, const EAXCHORUSPROPERTIES &props)
{
using Committer = ChorusFlangerEffect<EaxChorusTraits>;
Committer::Get(call, props);
}
-template<>
-void ChorusCommitter::Set(const EaxCall &call, EaxEffectProps &props)
+void EaxChorusCommitter::Set(const EaxCall &call, EAXCHORUSPROPERTIES &props)
{
using Committer = ChorusFlangerEffect<EaxChorusTraits>;
Committer::Set(call, props);
@@ -679,29 +624,25 @@ template<>
throw Exception{message};
}
-template<>
-bool FlangerCommitter::commit(const EaxEffectProps &props)
+bool EaxFlangerCommitter::commit(const EAXFLANGERPROPERTIES &props)
{
using Committer = ChorusFlangerEffect<EaxFlangerTraits>;
- return Committer::Commit(props, mEaxProps, mAlProps);
+ return Committer::Commit(props, mEaxProps, mAlProps.emplace<FlangerProps>());
}
-template<>
-void FlangerCommitter::SetDefaults(EaxEffectProps &props)
+void EaxFlangerCommitter::SetDefaults(EaxEffectProps &props)
{
using Committer = ChorusFlangerEffect<EaxFlangerTraits>;
Committer::SetDefaults(props);
}
-template<>
-void FlangerCommitter::Get(const EaxCall &call, const EaxEffectProps &props)
+void EaxFlangerCommitter::Get(const EaxCall &call, const EAXFLANGERPROPERTIES &props)
{
using Committer = ChorusFlangerEffect<EaxFlangerTraits>;
Committer::Get(call, props);
}
-template<>
-void FlangerCommitter::Set(const EaxCall &call, EaxEffectProps &props)
+void EaxFlangerCommitter::Set(const EaxCall &call, EAXFLANGERPROPERTIES &props)
{
using Committer = ChorusFlangerEffect<EaxFlangerTraits>;
Committer::Set(call, props);
diff --git a/al/effects/compressor.cpp b/al/effects/compressor.cpp
index ca8af84f..9fcc8c61 100644
--- a/al/effects/compressor.cpp
+++ b/al/effects/compressor.cpp
@@ -16,14 +16,25 @@
namespace {
-void Compressor_setParami(EffectProps *props, ALenum param, int val)
+EffectProps genDefaultProps() noexcept
+{
+ CompressorProps props{};
+ props.OnOff = AL_COMPRESSOR_DEFAULT_ONOFF;
+ return props;
+}
+
+} // namespace
+
+const EffectProps CompressorEffectProps{genDefaultProps()};
+
+void EffectHandler::SetParami(CompressorProps &props, ALenum param, int val)
{
switch(param)
{
case AL_COMPRESSOR_ONOFF:
if(!(val >= AL_COMPRESSOR_MIN_ONOFF && val <= AL_COMPRESSOR_MAX_ONOFF))
throw effect_exception{AL_INVALID_VALUE, "Compressor state out of range"};
- props->Compressor.OnOff = (val != AL_FALSE);
+ props.OnOff = (val != AL_FALSE);
break;
default:
@@ -31,22 +42,22 @@ void Compressor_setParami(EffectProps *props, ALenum param, int val)
param};
}
}
-void Compressor_setParamiv(EffectProps *props, ALenum param, const int *vals)
-{ Compressor_setParami(props, param, vals[0]); }
-void Compressor_setParamf(EffectProps*, ALenum param, float)
+void EffectHandler::SetParamiv(CompressorProps &props, ALenum param, const int *vals)
+{ SetParami(props, param, vals[0]); }
+void EffectHandler::SetParamf(CompressorProps&, ALenum param, float)
{ throw effect_exception{AL_INVALID_ENUM, "Invalid compressor float property 0x%04x", param}; }
-void Compressor_setParamfv(EffectProps*, ALenum param, const float*)
+void EffectHandler::SetParamfv(CompressorProps&, ALenum param, const float*)
{
throw effect_exception{AL_INVALID_ENUM, "Invalid compressor float-vector property 0x%04x",
param};
}
-void Compressor_getParami(const EffectProps *props, ALenum param, int *val)
+void EffectHandler::GetParami(const CompressorProps &props, ALenum param, int *val)
{
switch(param)
{
case AL_COMPRESSOR_ONOFF:
- *val = props->Compressor.OnOff;
+ *val = props.OnOff;
break;
default:
@@ -54,28 +65,16 @@ void Compressor_getParami(const EffectProps *props, ALenum param, int *val)
param};
}
}
-void Compressor_getParamiv(const EffectProps *props, ALenum param, int *vals)
-{ Compressor_getParami(props, param, vals); }
-void Compressor_getParamf(const EffectProps*, ALenum param, float*)
+void EffectHandler::GetParamiv(const CompressorProps &props, ALenum param, int *vals)
+{ GetParami(props, param, vals); }
+void EffectHandler::GetParamf(const CompressorProps&, ALenum param, float*)
{ throw effect_exception{AL_INVALID_ENUM, "Invalid compressor float property 0x%04x", param}; }
-void Compressor_getParamfv(const EffectProps*, ALenum param, float*)
+void EffectHandler::GetParamfv(const CompressorProps&, ALenum param, float*)
{
throw effect_exception{AL_INVALID_ENUM, "Invalid compressor float-vector property 0x%04x",
param};
}
-EffectProps genDefaultProps() noexcept
-{
- EffectProps props{};
- props.Compressor.OnOff = AL_COMPRESSOR_DEFAULT_ONOFF;
- return props;
-}
-
-} // namespace
-
-DEFINE_ALEFFECT_VTABLE(Compressor);
-
-const EffectProps CompressorEffectProps{genDefaultProps()};
#ifdef ALSOFT_EAX
namespace {
@@ -115,28 +114,24 @@ template<>
throw Exception{message};
}
-template<>
-bool CompressorCommitter::commit(const EaxEffectProps &props)
+bool EaxCompressorCommitter::commit(const EAXAGCCOMPRESSORPROPERTIES &props)
{
- if(props == mEaxProps)
+ if(auto *cur = std::get_if<EAXAGCCOMPRESSORPROPERTIES>(&mEaxProps); cur && *cur == props)
return false;
mEaxProps = props;
+ mAlProps = CompressorProps{props.ulOnOff != 0};
- mAlProps.Compressor.OnOff = (std::get<EAXAGCCOMPRESSORPROPERTIES>(props).ulOnOff != 0);
return true;
}
-template<>
-void CompressorCommitter::SetDefaults(EaxEffectProps &props)
+void EaxCompressorCommitter::SetDefaults(EaxEffectProps &props)
{
props = EAXAGCCOMPRESSORPROPERTIES{EAXAGCCOMPRESSOR_DEFAULTONOFF};
}
-template<>
-void CompressorCommitter::Get(const EaxCall &call, const EaxEffectProps &props_)
+void EaxCompressorCommitter::Get(const EaxCall &call, const EAXAGCCOMPRESSORPROPERTIES &props)
{
- auto &props = std::get<EAXAGCCOMPRESSORPROPERTIES>(props_);
switch(call.get_property_id())
{
case EAXAGCCOMPRESSOR_NONE: break;
@@ -146,10 +141,8 @@ void CompressorCommitter::Get(const EaxCall &call, const EaxEffectProps &props_)
}
}
-template<>
-void CompressorCommitter::Set(const EaxCall &call, EaxEffectProps &props_)
+void EaxCompressorCommitter::Set(const EaxCall &call, EAXAGCCOMPRESSORPROPERTIES &props)
{
- auto &props = std::get<EAXAGCCOMPRESSORPROPERTIES>(props_);
switch(call.get_property_id())
{
case EAXAGCCOMPRESSOR_NONE: break;
diff --git a/al/effects/convolution.cpp b/al/effects/convolution.cpp
index 9c091e53..1f8d1111 100644
--- a/al/effects/convolution.cpp
+++ b/al/effects/convolution.cpp
@@ -12,33 +12,45 @@
namespace {
-void Convolution_setParami(EffectProps* /*props*/, ALenum param, int /*val*/)
+EffectProps genDefaultProps() noexcept
+{
+ ConvolutionProps props{};
+ props.OrientAt = {0.0f, 0.0f, -1.0f};
+ props.OrientUp = {0.0f, 1.0f, 0.0f};
+ return props;
+}
+
+} // namespace
+
+const EffectProps ConvolutionEffectProps{genDefaultProps()};
+
+void EffectHandler::SetParami(ConvolutionProps& /*props*/, ALenum param, int /*val*/)
{
switch(param)
{
default:
- throw effect_exception{AL_INVALID_ENUM, "Invalid null effect integer property 0x%04x",
+ throw effect_exception{AL_INVALID_ENUM, "Invalid convolution effect integer property 0x%04x",
param};
}
}
-void Convolution_setParamiv(EffectProps *props, ALenum param, const int *vals)
+void EffectHandler::SetParamiv(ConvolutionProps &props, ALenum param, const int *vals)
{
switch(param)
{
default:
- Convolution_setParami(props, param, vals[0]);
+ SetParami(props, param, vals[0]);
}
}
-void Convolution_setParamf(EffectProps* /*props*/, ALenum param, float /*val*/)
+void EffectHandler::SetParamf(ConvolutionProps& /*props*/, ALenum param, float /*val*/)
{
switch(param)
{
default:
- throw effect_exception{AL_INVALID_ENUM, "Invalid null effect float property 0x%04x",
+ throw effect_exception{AL_INVALID_ENUM, "Invalid convolution effect float property 0x%04x",
param};
}
}
-void Convolution_setParamfv(EffectProps *props, ALenum param, const float *values)
+void EffectHandler::SetParamfv(ConvolutionProps &props, ALenum param, const float *values)
{
switch(param)
{
@@ -47,73 +59,59 @@ void Convolution_setParamfv(EffectProps *props, ALenum param, const float *value
&& std::isfinite(values[3]) && std::isfinite(values[4]) && std::isfinite(values[5])))
throw effect_exception{AL_INVALID_VALUE, "Property 0x%04x value out of range", param};
- props->Convolution.OrientAt[0] = values[0];
- props->Convolution.OrientAt[1] = values[1];
- props->Convolution.OrientAt[2] = values[2];
- props->Convolution.OrientUp[0] = values[3];
- props->Convolution.OrientUp[1] = values[4];
- props->Convolution.OrientUp[2] = values[5];
+ props.OrientAt[0] = values[0];
+ props.OrientAt[1] = values[1];
+ props.OrientAt[2] = values[2];
+ props.OrientUp[0] = values[3];
+ props.OrientUp[1] = values[4];
+ props.OrientUp[2] = values[5];
break;
default:
- Convolution_setParamf(props, param, values[0]);
+ SetParamf(props, param, values[0]);
}
}
-void Convolution_getParami(const EffectProps* /*props*/, ALenum param, int* /*val*/)
+void EffectHandler::GetParami(const ConvolutionProps& /*props*/, ALenum param, int* /*val*/)
{
switch(param)
{
default:
- throw effect_exception{AL_INVALID_ENUM, "Invalid null effect integer property 0x%04x",
+ throw effect_exception{AL_INVALID_ENUM, "Invalid convolution effect integer property 0x%04x",
param};
}
}
-void Convolution_getParamiv(const EffectProps *props, ALenum param, int *vals)
+void EffectHandler::GetParamiv(const ConvolutionProps &props, ALenum param, int *vals)
{
switch(param)
{
default:
- Convolution_getParami(props, param, vals);
+ GetParami(props, param, vals);
}
}
-void Convolution_getParamf(const EffectProps* /*props*/, ALenum param, float* /*val*/)
+void EffectHandler::GetParamf(const ConvolutionProps& /*props*/, ALenum param, float* /*val*/)
{
switch(param)
{
default:
- throw effect_exception{AL_INVALID_ENUM, "Invalid null effect float property 0x%04x",
+ throw effect_exception{AL_INVALID_ENUM, "Invalid convolution effect float property 0x%04x",
param};
}
}
-void Convolution_getParamfv(const EffectProps *props, ALenum param, float *values)
+void EffectHandler::GetParamfv(const ConvolutionProps &props, ALenum param, float *values)
{
switch(param)
{
case AL_CONVOLUTION_ORIENTATION_SOFT:
- values[0] = props->Convolution.OrientAt[0];
- values[1] = props->Convolution.OrientAt[1];
- values[2] = props->Convolution.OrientAt[2];
- values[3] = props->Convolution.OrientUp[0];
- values[4] = props->Convolution.OrientUp[1];
- values[5] = props->Convolution.OrientUp[2];
+ values[0] = props.OrientAt[0];
+ values[1] = props.OrientAt[1];
+ values[2] = props.OrientAt[2];
+ values[3] = props.OrientUp[0];
+ values[4] = props.OrientUp[1];
+ values[5] = props.OrientUp[2];
break;
default:
- Convolution_getParamf(props, param, values);
+ GetParamf(props, param, values);
}
}
-
-EffectProps genDefaultProps() noexcept
-{
- EffectProps props{};
- props.Convolution.OrientAt = {0.0f, 0.0f, -1.0f};
- props.Convolution.OrientUp = {0.0f, 1.0f, 0.0f};
- return props;
-}
-
-} // namespace
-
-DEFINE_ALEFFECT_VTABLE(Convolution);
-
-const EffectProps ConvolutionEffectProps{genDefaultProps()};
diff --git a/al/effects/dedicated.cpp b/al/effects/dedicated.cpp
index db57003c..518c224c 100644
--- a/al/effects/dedicated.cpp
+++ b/al/effects/dedicated.cpp
@@ -12,61 +12,115 @@
namespace {
-void Dedicated_setParami(EffectProps*, ALenum param, int)
+EffectProps genDefaultDialogProps() noexcept
+{
+ DedicatedDialogProps props{};
+ props.Gain = 1.0f;
+ return props;
+}
+
+EffectProps genDefaultLfeProps() noexcept
+{
+ DedicatedLfeProps props{};
+ props.Gain = 1.0f;
+ return props;
+}
+
+} // namespace
+
+const EffectProps DedicatedDialogEffectProps{genDefaultDialogProps()};
+
+void EffectHandler::SetParami(DedicatedDialogProps&, ALenum param, int)
{ throw effect_exception{AL_INVALID_ENUM, "Invalid dedicated integer property 0x%04x", param}; }
-void Dedicated_setParamiv(EffectProps*, ALenum param, const int*)
+void EffectHandler::SetParamiv(DedicatedDialogProps&, ALenum param, const int*)
{
throw effect_exception{AL_INVALID_ENUM, "Invalid dedicated integer-vector property 0x%04x",
param};
}
-void Dedicated_setParamf(EffectProps *props, ALenum param, float val)
+void EffectHandler::SetParamf(DedicatedDialogProps &props, ALenum param, float val)
{
switch(param)
{
case AL_DEDICATED_GAIN:
if(!(val >= 0.0f && std::isfinite(val)))
throw effect_exception{AL_INVALID_VALUE, "Dedicated gain out of range"};
- props->Dedicated.Gain = val;
+ props.Gain = val;
break;
default:
throw effect_exception{AL_INVALID_ENUM, "Invalid dedicated float property 0x%04x", param};
}
}
-void Dedicated_setParamfv(EffectProps *props, ALenum param, const float *vals)
-{ Dedicated_setParamf(props, param, vals[0]); }
+void EffectHandler::SetParamfv(DedicatedDialogProps &props, ALenum param, const float *vals)
+{ SetParamf(props, param, vals[0]); }
-void Dedicated_getParami(const EffectProps*, ALenum param, int*)
+void EffectHandler::GetParami(const DedicatedDialogProps&, ALenum param, int*)
{ throw effect_exception{AL_INVALID_ENUM, "Invalid dedicated integer property 0x%04x", param}; }
-void Dedicated_getParamiv(const EffectProps*, ALenum param, int*)
+void EffectHandler::GetParamiv(const DedicatedDialogProps&, ALenum param, int*)
{
throw effect_exception{AL_INVALID_ENUM, "Invalid dedicated integer-vector property 0x%04x",
param};
}
-void Dedicated_getParamf(const EffectProps *props, ALenum param, float *val)
+void EffectHandler::GetParamf(const DedicatedDialogProps &props, ALenum param, float *val)
{
switch(param)
{
case AL_DEDICATED_GAIN:
- *val = props->Dedicated.Gain;
+ *val = props.Gain;
break;
default:
throw effect_exception{AL_INVALID_ENUM, "Invalid dedicated float property 0x%04x", param};
}
}
-void Dedicated_getParamfv(const EffectProps *props, ALenum param, float *vals)
-{ Dedicated_getParamf(props, param, vals); }
+void EffectHandler::GetParamfv(const DedicatedDialogProps &props, ALenum param, float *vals)
+{ GetParamf(props, param, vals); }
-EffectProps genDefaultProps() noexcept
+
+const EffectProps DedicatedLfeEffectProps{genDefaultLfeProps()};
+
+void EffectHandler::SetParami(DedicatedLfeProps&, ALenum param, int)
+{ throw effect_exception{AL_INVALID_ENUM, "Invalid dedicated integer property 0x%04x", param}; }
+void EffectHandler::SetParamiv(DedicatedLfeProps&, ALenum param, const int*)
{
- EffectProps props{};
- props.Dedicated.Gain = 1.0f;
- return props;
+ throw effect_exception{AL_INVALID_ENUM, "Invalid dedicated integer-vector property 0x%04x",
+ param};
}
+void EffectHandler::SetParamf(DedicatedLfeProps &props, ALenum param, float val)
+{
+ switch(param)
+ {
+ case AL_DEDICATED_GAIN:
+ if(!(val >= 0.0f && std::isfinite(val)))
+ throw effect_exception{AL_INVALID_VALUE, "Dedicated gain out of range"};
+ props.Gain = val;
+ break;
-} // namespace
+ default:
+ throw effect_exception{AL_INVALID_ENUM, "Invalid dedicated float property 0x%04x", param};
+ }
+}
+void EffectHandler::SetParamfv(DedicatedLfeProps &props, ALenum param, const float *vals)
+{ SetParamf(props, param, vals[0]); }
-DEFINE_ALEFFECT_VTABLE(Dedicated);
+void EffectHandler::GetParami(const DedicatedLfeProps&, ALenum param, int*)
+{ throw effect_exception{AL_INVALID_ENUM, "Invalid dedicated integer property 0x%04x", param}; }
+void EffectHandler::GetParamiv(const DedicatedLfeProps&, ALenum param, int*)
+{
+ throw effect_exception{AL_INVALID_ENUM, "Invalid dedicated integer-vector property 0x%04x",
+ param};
+}
+void EffectHandler::GetParamf(const DedicatedLfeProps &props, ALenum param, float *val)
+{
+ switch(param)
+ {
+ case AL_DEDICATED_GAIN:
+ *val = props.Gain;
+ break;
-const EffectProps DedicatedEffectProps{genDefaultProps()};
+ default:
+ throw effect_exception{AL_INVALID_ENUM, "Invalid dedicated float property 0x%04x", param};
+ }
+}
+void EffectHandler::GetParamfv(const DedicatedLfeProps &props, ALenum param, float *vals)
+{ GetParamf(props, param, vals); }
diff --git a/al/effects/distortion.cpp b/al/effects/distortion.cpp
index e046d8e7..534b6c24 100644
--- a/al/effects/distortion.cpp
+++ b/al/effects/distortion.cpp
@@ -16,108 +16,93 @@
namespace {
-void Distortion_setParami(EffectProps*, ALenum param, int)
+EffectProps genDefaultProps() noexcept
+{
+ DistortionProps props{};
+ props.Edge = AL_DISTORTION_DEFAULT_EDGE;
+ props.Gain = AL_DISTORTION_DEFAULT_GAIN;
+ props.LowpassCutoff = AL_DISTORTION_DEFAULT_LOWPASS_CUTOFF;
+ props.EQCenter = AL_DISTORTION_DEFAULT_EQCENTER;
+ props.EQBandwidth = AL_DISTORTION_DEFAULT_EQBANDWIDTH;
+ return props;
+}
+
+} // namespace
+
+const EffectProps DistortionEffectProps{genDefaultProps()};
+
+void EffectHandler::SetParami(DistortionProps&, ALenum param, int)
{ throw effect_exception{AL_INVALID_ENUM, "Invalid distortion integer property 0x%04x", param}; }
-void Distortion_setParamiv(EffectProps*, ALenum param, const int*)
+void EffectHandler::SetParamiv(DistortionProps&, ALenum param, const int*)
{
throw effect_exception{AL_INVALID_ENUM, "Invalid distortion integer-vector property 0x%04x",
param};
}
-void Distortion_setParamf(EffectProps *props, ALenum param, float val)
+void EffectHandler::SetParamf(DistortionProps &props, ALenum param, float val)
{
switch(param)
{
case AL_DISTORTION_EDGE:
if(!(val >= AL_DISTORTION_MIN_EDGE && val <= AL_DISTORTION_MAX_EDGE))
throw effect_exception{AL_INVALID_VALUE, "Distortion edge out of range"};
- props->Distortion.Edge = val;
+ props.Edge = val;
break;
case AL_DISTORTION_GAIN:
if(!(val >= AL_DISTORTION_MIN_GAIN && val <= AL_DISTORTION_MAX_GAIN))
throw effect_exception{AL_INVALID_VALUE, "Distortion gain out of range"};
- props->Distortion.Gain = val;
+ props.Gain = val;
break;
case AL_DISTORTION_LOWPASS_CUTOFF:
if(!(val >= AL_DISTORTION_MIN_LOWPASS_CUTOFF && val <= AL_DISTORTION_MAX_LOWPASS_CUTOFF))
throw effect_exception{AL_INVALID_VALUE, "Distortion low-pass cutoff out of range"};
- props->Distortion.LowpassCutoff = val;
+ props.LowpassCutoff = val;
break;
case AL_DISTORTION_EQCENTER:
if(!(val >= AL_DISTORTION_MIN_EQCENTER && val <= AL_DISTORTION_MAX_EQCENTER))
throw effect_exception{AL_INVALID_VALUE, "Distortion EQ center out of range"};
- props->Distortion.EQCenter = val;
+ props.EQCenter = val;
break;
case AL_DISTORTION_EQBANDWIDTH:
if(!(val >= AL_DISTORTION_MIN_EQBANDWIDTH && val <= AL_DISTORTION_MAX_EQBANDWIDTH))
throw effect_exception{AL_INVALID_VALUE, "Distortion EQ bandwidth out of range"};
- props->Distortion.EQBandwidth = val;
+ props.EQBandwidth = val;
break;
default:
throw effect_exception{AL_INVALID_ENUM, "Invalid distortion float property 0x%04x", param};
}
}
-void Distortion_setParamfv(EffectProps *props, ALenum param, const float *vals)
-{ Distortion_setParamf(props, param, vals[0]); }
+void EffectHandler::SetParamfv(DistortionProps &props, ALenum param, const float *vals)
+{ SetParamf(props, param, vals[0]); }
-void Distortion_getParami(const EffectProps*, ALenum param, int*)
+void EffectHandler::GetParami(const DistortionProps&, ALenum param, int*)
{ throw effect_exception{AL_INVALID_ENUM, "Invalid distortion integer property 0x%04x", param}; }
-void Distortion_getParamiv(const EffectProps*, ALenum param, int*)
+void EffectHandler::GetParamiv(const DistortionProps&, ALenum param, int*)
{
throw effect_exception{AL_INVALID_ENUM, "Invalid distortion integer-vector property 0x%04x",
param};
}
-void Distortion_getParamf(const EffectProps *props, ALenum param, float *val)
+void EffectHandler::GetParamf(const DistortionProps &props, ALenum param, float *val)
{
switch(param)
{
- case AL_DISTORTION_EDGE:
- *val = props->Distortion.Edge;
- break;
-
- case AL_DISTORTION_GAIN:
- *val = props->Distortion.Gain;
- break;
-
- case AL_DISTORTION_LOWPASS_CUTOFF:
- *val = props->Distortion.LowpassCutoff;
- break;
-
- case AL_DISTORTION_EQCENTER:
- *val = props->Distortion.EQCenter;
- break;
-
- case AL_DISTORTION_EQBANDWIDTH:
- *val = props->Distortion.EQBandwidth;
- break;
+ case AL_DISTORTION_EDGE: *val = props.Edge; break;
+ case AL_DISTORTION_GAIN: *val = props.Gain; break;
+ case AL_DISTORTION_LOWPASS_CUTOFF: *val = props.LowpassCutoff; break;
+ case AL_DISTORTION_EQCENTER: *val = props.EQCenter; break;
+ case AL_DISTORTION_EQBANDWIDTH: *val = props.EQBandwidth; break;
default:
throw effect_exception{AL_INVALID_ENUM, "Invalid distortion float property 0x%04x", param};
}
}
-void Distortion_getParamfv(const EffectProps *props, ALenum param, float *vals)
-{ Distortion_getParamf(props, param, vals); }
-
-EffectProps genDefaultProps() noexcept
-{
- EffectProps props{};
- props.Distortion.Edge = AL_DISTORTION_DEFAULT_EDGE;
- props.Distortion.Gain = AL_DISTORTION_DEFAULT_GAIN;
- props.Distortion.LowpassCutoff = AL_DISTORTION_DEFAULT_LOWPASS_CUTOFF;
- props.Distortion.EQCenter = AL_DISTORTION_DEFAULT_EQCENTER;
- props.Distortion.EQBandwidth = AL_DISTORTION_DEFAULT_EQBANDWIDTH;
- return props;
-}
+void EffectHandler::GetParamfv(const DistortionProps &props, ALenum param, float *vals)
+{ GetParamf(props, param, vals); }
-} // namespace
-
-DEFINE_ALEFFECT_VTABLE(Distortion);
-
-const EffectProps DistortionEffectProps{genDefaultProps()};
#ifdef ALSOFT_EAX
namespace {
@@ -204,26 +189,26 @@ template<>
throw Exception{message};
}
-template<>
-bool DistortionCommitter::commit(const EaxEffectProps &props)
+bool EaxDistortionCommitter::commit(const EAXDISTORTIONPROPERTIES &props)
{
- if(props == mEaxProps)
+ if(auto *cur = std::get_if<EAXDISTORTIONPROPERTIES>(&mEaxProps); cur && *cur == props)
return false;
mEaxProps = props;
-
- auto &eaxprops = std::get<EAXDISTORTIONPROPERTIES>(props);
- mAlProps.Distortion.Edge = eaxprops.flEdge;
- mAlProps.Distortion.Gain = level_mb_to_gain(static_cast<float>(eaxprops.lGain));
- mAlProps.Distortion.LowpassCutoff = eaxprops.flLowPassCutOff;
- mAlProps.Distortion.EQCenter = eaxprops.flEQCenter;
- mAlProps.Distortion.EQBandwidth = eaxprops.flEdge;
+ mAlProps = [&]{
+ DistortionProps ret{};
+ ret.Edge = props.flEdge;
+ ret.Gain = level_mb_to_gain(static_cast<float>(props.lGain));
+ ret.LowpassCutoff = props.flLowPassCutOff;
+ ret.EQCenter = props.flEQCenter;
+ ret.EQBandwidth = props.flEdge;
+ return ret;
+ }();
return true;
}
-template<>
-void DistortionCommitter::SetDefaults(EaxEffectProps &props)
+void EaxDistortionCommitter::SetDefaults(EaxEffectProps &props)
{
static constexpr EAXDISTORTIONPROPERTIES defprops{[]
{
@@ -238,10 +223,8 @@ void DistortionCommitter::SetDefaults(EaxEffectProps &props)
props = defprops;
}
-template<>
-void DistortionCommitter::Get(const EaxCall &call, const EaxEffectProps &props_)
+void EaxDistortionCommitter::Get(const EaxCall &call, const EAXDISTORTIONPROPERTIES &props)
{
- auto &props = std::get<EAXDISTORTIONPROPERTIES>(props_);
switch(call.get_property_id())
{
case EAXDISTORTION_NONE: break;
@@ -255,10 +238,8 @@ void DistortionCommitter::Get(const EaxCall &call, const EaxEffectProps &props_)
}
}
-template<>
-void DistortionCommitter::Set(const EaxCall &call, EaxEffectProps &props_)
+void EaxDistortionCommitter::Set(const EaxCall &call, EAXDISTORTIONPROPERTIES &props)
{
- auto &props = std::get<EAXDISTORTIONPROPERTIES>(props_);
switch(call.get_property_id())
{
case EAXDISTORTION_NONE: break;
diff --git a/al/effects/echo.cpp b/al/effects/echo.cpp
index 48aacef3..9412039b 100644
--- a/al/effects/echo.cpp
+++ b/al/effects/echo.cpp
@@ -19,102 +19,87 @@ namespace {
static_assert(EchoMaxDelay >= AL_ECHO_MAX_DELAY, "Echo max delay too short");
static_assert(EchoMaxLRDelay >= AL_ECHO_MAX_LRDELAY, "Echo max left-right delay too short");
-void Echo_setParami(EffectProps*, ALenum param, int)
+EffectProps genDefaultProps() noexcept
+{
+ EchoProps props{};
+ props.Delay = AL_ECHO_DEFAULT_DELAY;
+ props.LRDelay = AL_ECHO_DEFAULT_LRDELAY;
+ props.Damping = AL_ECHO_DEFAULT_DAMPING;
+ props.Feedback = AL_ECHO_DEFAULT_FEEDBACK;
+ props.Spread = AL_ECHO_DEFAULT_SPREAD;
+ return props;
+}
+
+} // namespace
+
+const EffectProps EchoEffectProps{genDefaultProps()};
+
+void EffectHandler::SetParami(EchoProps&, ALenum param, int)
{ throw effect_exception{AL_INVALID_ENUM, "Invalid echo integer property 0x%04x", param}; }
-void Echo_setParamiv(EffectProps*, ALenum param, const int*)
+void EffectHandler::SetParamiv(EchoProps&, ALenum param, const int*)
{ throw effect_exception{AL_INVALID_ENUM, "Invalid echo integer-vector property 0x%04x", param}; }
-void Echo_setParamf(EffectProps *props, ALenum param, float val)
+void EffectHandler::SetParamf(EchoProps &props, ALenum param, float val)
{
switch(param)
{
case AL_ECHO_DELAY:
if(!(val >= AL_ECHO_MIN_DELAY && val <= AL_ECHO_MAX_DELAY))
throw effect_exception{AL_INVALID_VALUE, "Echo delay out of range"};
- props->Echo.Delay = val;
+ props.Delay = val;
break;
case AL_ECHO_LRDELAY:
if(!(val >= AL_ECHO_MIN_LRDELAY && val <= AL_ECHO_MAX_LRDELAY))
throw effect_exception{AL_INVALID_VALUE, "Echo LR delay out of range"};
- props->Echo.LRDelay = val;
+ props.LRDelay = val;
break;
case AL_ECHO_DAMPING:
if(!(val >= AL_ECHO_MIN_DAMPING && val <= AL_ECHO_MAX_DAMPING))
throw effect_exception{AL_INVALID_VALUE, "Echo damping out of range"};
- props->Echo.Damping = val;
+ props.Damping = val;
break;
case AL_ECHO_FEEDBACK:
if(!(val >= AL_ECHO_MIN_FEEDBACK && val <= AL_ECHO_MAX_FEEDBACK))
throw effect_exception{AL_INVALID_VALUE, "Echo feedback out of range"};
- props->Echo.Feedback = val;
+ props.Feedback = val;
break;
case AL_ECHO_SPREAD:
if(!(val >= AL_ECHO_MIN_SPREAD && val <= AL_ECHO_MAX_SPREAD))
throw effect_exception{AL_INVALID_VALUE, "Echo spread out of range"};
- props->Echo.Spread = val;
+ props.Spread = val;
break;
default:
throw effect_exception{AL_INVALID_ENUM, "Invalid echo float property 0x%04x", param};
}
}
-void Echo_setParamfv(EffectProps *props, ALenum param, const float *vals)
-{ Echo_setParamf(props, param, vals[0]); }
+void EffectHandler::SetParamfv(EchoProps &props, ALenum param, const float *vals)
+{ SetParamf(props, param, vals[0]); }
-void Echo_getParami(const EffectProps*, ALenum param, int*)
+void EffectHandler::GetParami(const EchoProps&, ALenum param, int*)
{ throw effect_exception{AL_INVALID_ENUM, "Invalid echo integer property 0x%04x", param}; }
-void Echo_getParamiv(const EffectProps*, ALenum param, int*)
+void EffectHandler::GetParamiv(const EchoProps&, ALenum param, int*)
{ throw effect_exception{AL_INVALID_ENUM, "Invalid echo integer-vector property 0x%04x", param}; }
-void Echo_getParamf(const EffectProps *props, ALenum param, float *val)
+void EffectHandler::GetParamf(const EchoProps &props, ALenum param, float *val)
{
switch(param)
{
- case AL_ECHO_DELAY:
- *val = props->Echo.Delay;
- break;
-
- case AL_ECHO_LRDELAY:
- *val = props->Echo.LRDelay;
- break;
-
- case AL_ECHO_DAMPING:
- *val = props->Echo.Damping;
- break;
-
- case AL_ECHO_FEEDBACK:
- *val = props->Echo.Feedback;
- break;
-
- case AL_ECHO_SPREAD:
- *val = props->Echo.Spread;
- break;
+ case AL_ECHO_DELAY: *val = props.Delay; break;
+ case AL_ECHO_LRDELAY: *val = props.LRDelay; break;
+ case AL_ECHO_DAMPING: *val = props.Damping; break;
+ case AL_ECHO_FEEDBACK: *val = props.Feedback; break;
+ case AL_ECHO_SPREAD: *val = props.Spread; break;
default:
throw effect_exception{AL_INVALID_ENUM, "Invalid echo float property 0x%04x", param};
}
}
-void Echo_getParamfv(const EffectProps *props, ALenum param, float *vals)
-{ Echo_getParamf(props, param, vals); }
-
-EffectProps genDefaultProps() noexcept
-{
- EffectProps props{};
- props.Echo.Delay = AL_ECHO_DEFAULT_DELAY;
- props.Echo.LRDelay = AL_ECHO_DEFAULT_LRDELAY;
- props.Echo.Damping = AL_ECHO_DEFAULT_DAMPING;
- props.Echo.Feedback = AL_ECHO_DEFAULT_FEEDBACK;
- props.Echo.Spread = AL_ECHO_DEFAULT_SPREAD;
- return props;
-}
+void EffectHandler::GetParamfv(const EchoProps &props, ALenum param, float *vals)
+{ GetParamf(props, param, vals); }
-} // namespace
-
-DEFINE_ALEFFECT_VTABLE(Echo);
-
-const EffectProps EchoEffectProps{genDefaultProps()};
#ifdef ALSOFT_EAX
namespace {
@@ -201,26 +186,26 @@ template<>
throw Exception{message};
}
-template<>
-bool EchoCommitter::commit(const EaxEffectProps &props)
+bool EaxEchoCommitter::commit(const EAXECHOPROPERTIES &props)
{
- if(props == mEaxProps)
+ if(auto *cur = std::get_if<EAXECHOPROPERTIES>(&mEaxProps); cur && *cur == props)
return false;
mEaxProps = props;
-
- auto &eaxprops = std::get<EAXECHOPROPERTIES>(props);
- mAlProps.Echo.Delay = eaxprops.flDelay;
- mAlProps.Echo.LRDelay = eaxprops.flLRDelay;
- mAlProps.Echo.Damping = eaxprops.flDamping;
- mAlProps.Echo.Feedback = eaxprops.flFeedback;
- mAlProps.Echo.Spread = eaxprops.flSpread;
+ mAlProps = [&]{
+ EchoProps ret{};
+ ret.Delay = props.flDelay;
+ ret.LRDelay = props.flLRDelay;
+ ret.Damping = props.flDamping;
+ ret.Feedback = props.flFeedback;
+ ret.Spread = props.flSpread;
+ return ret;
+ }();
return true;
}
-template<>
-void EchoCommitter::SetDefaults(EaxEffectProps &props)
+void EaxEchoCommitter::SetDefaults(EaxEffectProps &props)
{
static constexpr EAXECHOPROPERTIES defprops{[]
{
@@ -235,10 +220,8 @@ void EchoCommitter::SetDefaults(EaxEffectProps &props)
props = defprops;
}
-template<>
-void EchoCommitter::Get(const EaxCall &call, const EaxEffectProps &props_)
+void EaxEchoCommitter::Get(const EaxCall &call, const EAXECHOPROPERTIES &props)
{
- auto &props = std::get<EAXECHOPROPERTIES>(props_);
switch(call.get_property_id())
{
case EAXECHO_NONE: break;
@@ -252,10 +235,8 @@ void EchoCommitter::Get(const EaxCall &call, const EaxEffectProps &props_)
}
}
-template<>
-void EchoCommitter::Set(const EaxCall &call, EaxEffectProps &props_)
+void EaxEchoCommitter::Set(const EaxCall &call, EAXECHOPROPERTIES &props)
{
- auto &props = std::get<EAXECHOPROPERTIES>(props_);
switch(call.get_property_id())
{
case EAXECHO_NONE: break;
diff --git a/al/effects/effects.h b/al/effects/effects.h
index 9d57dd82..38d47f86 100644
--- a/al/effects/effects.h
+++ b/al/effects/effects.h
@@ -3,52 +3,69 @@
#include "AL/al.h"
+#include "core/effects/base.h"
#include "core/except.h"
#ifdef ALSOFT_EAX
#include "al/eax/effect.h"
#endif // ALSOFT_EAX
-union EffectProps;
+struct EffectHandler {
+#define DECL_HANDLER(T) \
+ static void SetParami(T &props, ALenum param, int val); \
+ static void SetParamiv(T &props, ALenum param, const int *vals); \
+ static void SetParamf(T &props, ALenum param, float val); \
+ static void SetParamfv(T &props, ALenum param, const float *vals); \
+ static void GetParami(const T &props, ALenum param, int *val); \
+ static void GetParamiv(const T &props, ALenum param, int *vals); \
+ static void GetParamf(const T &props, ALenum param, float *val); \
+ static void GetParamfv(const T &props, ALenum param, float *vals);
+
+ DECL_HANDLER(std::monostate)
+ DECL_HANDLER(ReverbProps)
+ DECL_HANDLER(ChorusProps)
+ DECL_HANDLER(AutowahProps)
+ DECL_HANDLER(CompressorProps)
+ DECL_HANDLER(ConvolutionProps)
+ DECL_HANDLER(DedicatedDialogProps)
+ DECL_HANDLER(DedicatedLfeProps)
+ DECL_HANDLER(DistortionProps)
+ DECL_HANDLER(EchoProps)
+ DECL_HANDLER(EqualizerProps)
+ DECL_HANDLER(FlangerProps)
+ DECL_HANDLER(FshifterProps)
+ DECL_HANDLER(ModulatorProps)
+ DECL_HANDLER(PshifterProps)
+ DECL_HANDLER(VmorpherProps)
+#undef DECL_HANDLER
+
+ static void StdReverbSetParami(ReverbProps &props, ALenum param, int val);
+ static void StdReverbSetParamiv(ReverbProps &props, ALenum param, const int *vals);
+ static void StdReverbSetParamf(ReverbProps &props, ALenum param, float val);
+ static void StdReverbSetParamfv(ReverbProps &props, ALenum param, const float *vals);
+ static void StdReverbGetParami(const ReverbProps &props, ALenum param, int *val);
+ static void StdReverbGetParamiv(const ReverbProps &props, ALenum param, int *vals);
+ static void StdReverbGetParamf(const ReverbProps &props, ALenum param, float *val);
+ static void StdReverbGetParamfv(const ReverbProps &props, ALenum param, float *vals);
+};
class effect_exception final : public al::base_exception {
ALenum 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
effect_exception(ALenum code, const char *msg, ...);
~effect_exception() override;
- ALenum errorCode() const noexcept { return mErrorCode; }
+ [[nodiscard]] auto errorCode() const noexcept -> ALenum { return mErrorCode; }
};
-struct EffectVtable {
- void (*const setParami)(EffectProps *props, ALenum param, int val);
- void (*const setParamiv)(EffectProps *props, ALenum param, const int *vals);
- void (*const setParamf)(EffectProps *props, ALenum param, float val);
- void (*const setParamfv)(EffectProps *props, ALenum param, const float *vals);
-
- void (*const getParami)(const EffectProps *props, ALenum param, int *val);
- void (*const getParamiv)(const EffectProps *props, ALenum param, int *vals);
- void (*const getParamf)(const EffectProps *props, ALenum param, float *val);
- void (*const getParamfv)(const EffectProps *props, ALenum param, float *vals);
-};
-
-#define DEFINE_ALEFFECT_VTABLE(T) \
-const EffectVtable T##EffectVtable = { \
- T##_setParami, T##_setParamiv, \
- T##_setParamf, T##_setParamfv, \
- T##_getParami, T##_getParamiv, \
- T##_getParamf, T##_getParamfv, \
-}
-
-
/* Default properties for the given effect types. */
extern const EffectProps NullEffectProps;
extern const EffectProps ReverbEffectProps;
@@ -64,25 +81,8 @@ extern const EffectProps FshifterEffectProps;
extern const EffectProps ModulatorEffectProps;
extern const EffectProps PshifterEffectProps;
extern const EffectProps VmorpherEffectProps;
-extern const EffectProps DedicatedEffectProps;
+extern const EffectProps DedicatedDialogEffectProps;
+extern const EffectProps DedicatedLfeEffectProps;
extern const EffectProps ConvolutionEffectProps;
-/* Vtables to get/set properties for the given effect types. */
-extern const EffectVtable NullEffectVtable;
-extern const EffectVtable ReverbEffectVtable;
-extern const EffectVtable StdReverbEffectVtable;
-extern const EffectVtable AutowahEffectVtable;
-extern const EffectVtable ChorusEffectVtable;
-extern const EffectVtable CompressorEffectVtable;
-extern const EffectVtable DistortionEffectVtable;
-extern const EffectVtable EchoEffectVtable;
-extern const EffectVtable EqualizerEffectVtable;
-extern const EffectVtable FlangerEffectVtable;
-extern const EffectVtable FshifterEffectVtable;
-extern const EffectVtable ModulatorEffectVtable;
-extern const EffectVtable PshifterEffectVtable;
-extern const EffectVtable VmorpherEffectVtable;
-extern const EffectVtable DedicatedEffectVtable;
-extern const EffectVtable ConvolutionEffectVtable;
-
#endif /* AL_EFFECTS_EFFECTS_H */
diff --git a/al/effects/equalizer.cpp b/al/effects/equalizer.cpp
index 76d5bdef..74fc43fc 100644
--- a/al/effects/equalizer.cpp
+++ b/al/effects/equalizer.cpp
@@ -16,163 +16,133 @@
namespace {
-void Equalizer_setParami(EffectProps*, ALenum param, int)
+EffectProps genDefaultProps() noexcept
+{
+ EqualizerProps props{};
+ props.LowCutoff = AL_EQUALIZER_DEFAULT_LOW_CUTOFF;
+ props.LowGain = AL_EQUALIZER_DEFAULT_LOW_GAIN;
+ props.Mid1Center = AL_EQUALIZER_DEFAULT_MID1_CENTER;
+ props.Mid1Gain = AL_EQUALIZER_DEFAULT_MID1_GAIN;
+ props.Mid1Width = AL_EQUALIZER_DEFAULT_MID1_WIDTH;
+ props.Mid2Center = AL_EQUALIZER_DEFAULT_MID2_CENTER;
+ props.Mid2Gain = AL_EQUALIZER_DEFAULT_MID2_GAIN;
+ props.Mid2Width = AL_EQUALIZER_DEFAULT_MID2_WIDTH;
+ props.HighCutoff = AL_EQUALIZER_DEFAULT_HIGH_CUTOFF;
+ props.HighGain = AL_EQUALIZER_DEFAULT_HIGH_GAIN;
+ return props;
+}
+
+} // namespace
+
+const EffectProps EqualizerEffectProps{genDefaultProps()};
+
+void EffectHandler::SetParami(EqualizerProps&, ALenum param, int)
{ throw effect_exception{AL_INVALID_ENUM, "Invalid equalizer integer property 0x%04x", param}; }
-void Equalizer_setParamiv(EffectProps*, ALenum param, const int*)
+void EffectHandler::SetParamiv(EqualizerProps&, ALenum param, const int*)
{
throw effect_exception{AL_INVALID_ENUM, "Invalid equalizer integer-vector property 0x%04x",
param};
}
-void Equalizer_setParamf(EffectProps *props, ALenum param, float val)
+void EffectHandler::SetParamf(EqualizerProps &props, ALenum param, float val)
{
switch(param)
{
case AL_EQUALIZER_LOW_GAIN:
if(!(val >= AL_EQUALIZER_MIN_LOW_GAIN && val <= AL_EQUALIZER_MAX_LOW_GAIN))
throw effect_exception{AL_INVALID_VALUE, "Equalizer low-band gain out of range"};
- props->Equalizer.LowGain = val;
+ props.LowGain = val;
break;
case AL_EQUALIZER_LOW_CUTOFF:
if(!(val >= AL_EQUALIZER_MIN_LOW_CUTOFF && val <= AL_EQUALIZER_MAX_LOW_CUTOFF))
throw effect_exception{AL_INVALID_VALUE, "Equalizer low-band cutoff out of range"};
- props->Equalizer.LowCutoff = val;
+ props.LowCutoff = val;
break;
case AL_EQUALIZER_MID1_GAIN:
if(!(val >= AL_EQUALIZER_MIN_MID1_GAIN && val <= AL_EQUALIZER_MAX_MID1_GAIN))
throw effect_exception{AL_INVALID_VALUE, "Equalizer mid1-band gain out of range"};
- props->Equalizer.Mid1Gain = val;
+ props.Mid1Gain = val;
break;
case AL_EQUALIZER_MID1_CENTER:
if(!(val >= AL_EQUALIZER_MIN_MID1_CENTER && val <= AL_EQUALIZER_MAX_MID1_CENTER))
throw effect_exception{AL_INVALID_VALUE, "Equalizer mid1-band center out of range"};
- props->Equalizer.Mid1Center = val;
+ props.Mid1Center = val;
break;
case AL_EQUALIZER_MID1_WIDTH:
if(!(val >= AL_EQUALIZER_MIN_MID1_WIDTH && val <= AL_EQUALIZER_MAX_MID1_WIDTH))
throw effect_exception{AL_INVALID_VALUE, "Equalizer mid1-band width out of range"};
- props->Equalizer.Mid1Width = val;
+ props.Mid1Width = val;
break;
case AL_EQUALIZER_MID2_GAIN:
if(!(val >= AL_EQUALIZER_MIN_MID2_GAIN && val <= AL_EQUALIZER_MAX_MID2_GAIN))
throw effect_exception{AL_INVALID_VALUE, "Equalizer mid2-band gain out of range"};
- props->Equalizer.Mid2Gain = val;
+ props.Mid2Gain = val;
break;
case AL_EQUALIZER_MID2_CENTER:
if(!(val >= AL_EQUALIZER_MIN_MID2_CENTER && val <= AL_EQUALIZER_MAX_MID2_CENTER))
throw effect_exception{AL_INVALID_VALUE, "Equalizer mid2-band center out of range"};
- props->Equalizer.Mid2Center = val;
+ props.Mid2Center = val;
break;
case AL_EQUALIZER_MID2_WIDTH:
if(!(val >= AL_EQUALIZER_MIN_MID2_WIDTH && val <= AL_EQUALIZER_MAX_MID2_WIDTH))
throw effect_exception{AL_INVALID_VALUE, "Equalizer mid2-band width out of range"};
- props->Equalizer.Mid2Width = val;
+ props.Mid2Width = val;
break;
case AL_EQUALIZER_HIGH_GAIN:
if(!(val >= AL_EQUALIZER_MIN_HIGH_GAIN && val <= AL_EQUALIZER_MAX_HIGH_GAIN))
throw effect_exception{AL_INVALID_VALUE, "Equalizer high-band gain out of range"};
- props->Equalizer.HighGain = val;
+ props.HighGain = val;
break;
case AL_EQUALIZER_HIGH_CUTOFF:
if(!(val >= AL_EQUALIZER_MIN_HIGH_CUTOFF && val <= AL_EQUALIZER_MAX_HIGH_CUTOFF))
throw effect_exception{AL_INVALID_VALUE, "Equalizer high-band cutoff out of range"};
- props->Equalizer.HighCutoff = val;
+ props.HighCutoff = val;
break;
default:
throw effect_exception{AL_INVALID_ENUM, "Invalid equalizer float property 0x%04x", param};
}
}
-void Equalizer_setParamfv(EffectProps *props, ALenum param, const float *vals)
-{ Equalizer_setParamf(props, param, vals[0]); }
+void EffectHandler::SetParamfv(EqualizerProps &props, ALenum param, const float *vals)
+{ SetParamf(props, param, vals[0]); }
-void Equalizer_getParami(const EffectProps*, ALenum param, int*)
+void EffectHandler::GetParami(const EqualizerProps&, ALenum param, int*)
{ throw effect_exception{AL_INVALID_ENUM, "Invalid equalizer integer property 0x%04x", param}; }
-void Equalizer_getParamiv(const EffectProps*, ALenum param, int*)
+void EffectHandler::GetParamiv(const EqualizerProps&, ALenum param, int*)
{
throw effect_exception{AL_INVALID_ENUM, "Invalid equalizer integer-vector property 0x%04x",
param};
}
-void Equalizer_getParamf(const EffectProps *props, ALenum param, float *val)
+void EffectHandler::GetParamf(const EqualizerProps &props, ALenum param, float *val)
{
switch(param)
{
- case AL_EQUALIZER_LOW_GAIN:
- *val = props->Equalizer.LowGain;
- break;
-
- case AL_EQUALIZER_LOW_CUTOFF:
- *val = props->Equalizer.LowCutoff;
- break;
-
- case AL_EQUALIZER_MID1_GAIN:
- *val = props->Equalizer.Mid1Gain;
- break;
-
- case AL_EQUALIZER_MID1_CENTER:
- *val = props->Equalizer.Mid1Center;
- break;
-
- case AL_EQUALIZER_MID1_WIDTH:
- *val = props->Equalizer.Mid1Width;
- break;
-
- case AL_EQUALIZER_MID2_GAIN:
- *val = props->Equalizer.Mid2Gain;
- break;
-
- case AL_EQUALIZER_MID2_CENTER:
- *val = props->Equalizer.Mid2Center;
- break;
-
- case AL_EQUALIZER_MID2_WIDTH:
- *val = props->Equalizer.Mid2Width;
- break;
-
- case AL_EQUALIZER_HIGH_GAIN:
- *val = props->Equalizer.HighGain;
- break;
-
- case AL_EQUALIZER_HIGH_CUTOFF:
- *val = props->Equalizer.HighCutoff;
- break;
+ case AL_EQUALIZER_LOW_GAIN: *val = props.LowGain; break;
+ case AL_EQUALIZER_LOW_CUTOFF: *val = props.LowCutoff; break;
+ case AL_EQUALIZER_MID1_GAIN: *val = props.Mid1Gain; break;
+ case AL_EQUALIZER_MID1_CENTER: *val = props.Mid1Center; break;
+ case AL_EQUALIZER_MID1_WIDTH: *val = props.Mid1Width; break;
+ case AL_EQUALIZER_MID2_GAIN: *val = props.Mid2Gain; break;
+ case AL_EQUALIZER_MID2_CENTER: *val = props.Mid2Center; break;
+ case AL_EQUALIZER_MID2_WIDTH: *val = props.Mid2Width; break;
+ case AL_EQUALIZER_HIGH_GAIN: *val = props.HighGain; break;
+ case AL_EQUALIZER_HIGH_CUTOFF: *val = props.HighCutoff; break;
default:
throw effect_exception{AL_INVALID_ENUM, "Invalid equalizer float property 0x%04x", param};
}
}
-void Equalizer_getParamfv(const EffectProps *props, ALenum param, float *vals)
-{ Equalizer_getParamf(props, param, vals); }
-
-EffectProps genDefaultProps() noexcept
-{
- EffectProps props{};
- props.Equalizer.LowCutoff = AL_EQUALIZER_DEFAULT_LOW_CUTOFF;
- props.Equalizer.LowGain = AL_EQUALIZER_DEFAULT_LOW_GAIN;
- props.Equalizer.Mid1Center = AL_EQUALIZER_DEFAULT_MID1_CENTER;
- props.Equalizer.Mid1Gain = AL_EQUALIZER_DEFAULT_MID1_GAIN;
- props.Equalizer.Mid1Width = AL_EQUALIZER_DEFAULT_MID1_WIDTH;
- props.Equalizer.Mid2Center = AL_EQUALIZER_DEFAULT_MID2_CENTER;
- props.Equalizer.Mid2Gain = AL_EQUALIZER_DEFAULT_MID2_GAIN;
- props.Equalizer.Mid2Width = AL_EQUALIZER_DEFAULT_MID2_WIDTH;
- props.Equalizer.HighCutoff = AL_EQUALIZER_DEFAULT_HIGH_CUTOFF;
- props.Equalizer.HighGain = AL_EQUALIZER_DEFAULT_HIGH_GAIN;
- return props;
-}
+void EffectHandler::GetParamfv(const EqualizerProps &props, ALenum param, float *vals)
+{ GetParamf(props, param, vals); }
-} // namespace
-
-DEFINE_ALEFFECT_VTABLE(Equalizer);
-
-const EffectProps EqualizerEffectProps{genDefaultProps()};
#ifdef ALSOFT_EAX
namespace {
@@ -319,31 +289,31 @@ template<>
throw Exception{message};
}
-template<>
-bool EqualizerCommitter::commit(const EaxEffectProps &props)
+bool EaxEqualizerCommitter::commit(const EAXEQUALIZERPROPERTIES &props)
{
- if(props == mEaxProps)
+ if(auto *cur = std::get_if<EAXEQUALIZERPROPERTIES>(&mEaxProps); cur && *cur == props)
return false;
mEaxProps = props;
-
- auto &eaxprops = std::get<EAXEQUALIZERPROPERTIES>(props);
- mAlProps.Equalizer.LowGain = level_mb_to_gain(static_cast<float>(eaxprops.lLowGain));
- mAlProps.Equalizer.LowCutoff = eaxprops.flLowCutOff;
- mAlProps.Equalizer.Mid1Gain = level_mb_to_gain(static_cast<float>(eaxprops.lMid1Gain));
- mAlProps.Equalizer.Mid1Center = eaxprops.flMid1Center;
- mAlProps.Equalizer.Mid1Width = eaxprops.flMid1Width;
- mAlProps.Equalizer.Mid2Gain = level_mb_to_gain(static_cast<float>(eaxprops.lMid2Gain));
- mAlProps.Equalizer.Mid2Center = eaxprops.flMid2Center;
- mAlProps.Equalizer.Mid2Width = eaxprops.flMid2Width;
- mAlProps.Equalizer.HighGain = level_mb_to_gain(static_cast<float>(eaxprops.lHighGain));
- mAlProps.Equalizer.HighCutoff = eaxprops.flHighCutOff;
+ mAlProps = [&]{
+ EqualizerProps ret{};
+ ret.LowGain = level_mb_to_gain(static_cast<float>(props.lLowGain));
+ ret.LowCutoff = props.flLowCutOff;
+ ret.Mid1Gain = level_mb_to_gain(static_cast<float>(props.lMid1Gain));
+ ret.Mid1Center = props.flMid1Center;
+ ret.Mid1Width = props.flMid1Width;
+ ret.Mid2Gain = level_mb_to_gain(static_cast<float>(props.lMid2Gain));
+ ret.Mid2Center = props.flMid2Center;
+ ret.Mid2Width = props.flMid2Width;
+ ret.HighGain = level_mb_to_gain(static_cast<float>(props.lHighGain));
+ ret.HighCutoff = props.flHighCutOff;
+ return ret;
+ }();
return true;
}
-template<>
-void EqualizerCommitter::SetDefaults(EaxEffectProps &props)
+void EaxEqualizerCommitter::SetDefaults(EaxEffectProps &props)
{
static constexpr EAXEQUALIZERPROPERTIES defprops{[]
{
@@ -363,10 +333,8 @@ void EqualizerCommitter::SetDefaults(EaxEffectProps &props)
props = defprops;
}
-template<>
-void EqualizerCommitter::Get(const EaxCall &call, const EaxEffectProps &props_)
+void EaxEqualizerCommitter::Get(const EaxCall &call, const EAXEQUALIZERPROPERTIES &props)
{
- auto &props = std::get<EAXEQUALIZERPROPERTIES>(props_);
switch(call.get_property_id())
{
case EAXEQUALIZER_NONE: break;
@@ -385,10 +353,8 @@ void EqualizerCommitter::Get(const EaxCall &call, const EaxEffectProps &props_)
}
}
-template<>
-void EqualizerCommitter::Set(const EaxCall &call, EaxEffectProps &props_)
+void EaxEqualizerCommitter::Set(const EaxCall &call, EAXEQUALIZERPROPERTIES &props)
{
- auto &props = std::get<EAXEQUALIZERPROPERTIES>(props_);
switch(call.get_property_id())
{
case EAXEQUALIZER_NONE: break;
diff --git a/al/effects/fshifter.cpp b/al/effects/fshifter.cpp
index 37c372c3..556244ac 100644
--- a/al/effects/fshifter.cpp
+++ b/al/effects/fshifter.cpp
@@ -41,31 +41,26 @@ ALenum EnumFromDirection(FShifterDirection dir)
throw std::runtime_error{"Invalid direction: "+std::to_string(static_cast<int>(dir))};
}
-void Fshifter_setParamf(EffectProps *props, ALenum param, float val)
+EffectProps genDefaultProps() noexcept
{
- switch(param)
- {
- case AL_FREQUENCY_SHIFTER_FREQUENCY:
- if(!(val >= AL_FREQUENCY_SHIFTER_MIN_FREQUENCY && val <= AL_FREQUENCY_SHIFTER_MAX_FREQUENCY))
- throw effect_exception{AL_INVALID_VALUE, "Frequency shifter frequency out of range"};
- props->Fshifter.Frequency = val;
- break;
-
- default:
- throw effect_exception{AL_INVALID_ENUM, "Invalid frequency shifter float property 0x%04x",
- param};
- }
+ FshifterProps props{};
+ props.Frequency = AL_FREQUENCY_SHIFTER_DEFAULT_FREQUENCY;
+ props.LeftDirection = DirectionFromEmum(AL_FREQUENCY_SHIFTER_DEFAULT_LEFT_DIRECTION).value();
+ props.RightDirection = DirectionFromEmum(AL_FREQUENCY_SHIFTER_DEFAULT_RIGHT_DIRECTION).value();
+ return props;
}
-void Fshifter_setParamfv(EffectProps *props, ALenum param, const float *vals)
-{ Fshifter_setParamf(props, param, vals[0]); }
-void Fshifter_setParami(EffectProps *props, ALenum param, int val)
+} // namespace
+
+const EffectProps FshifterEffectProps{genDefaultProps()};
+
+void EffectHandler::SetParami(FshifterProps &props, ALenum param, int val)
{
switch(param)
{
case AL_FREQUENCY_SHIFTER_LEFT_DIRECTION:
if(auto diropt = DirectionFromEmum(val))
- props->Fshifter.LeftDirection = *diropt;
+ props.LeftDirection = *diropt;
else
throw effect_exception{AL_INVALID_VALUE,
"Unsupported frequency shifter left direction: 0x%04x", val};
@@ -73,7 +68,7 @@ void Fshifter_setParami(EffectProps *props, ALenum param, int val)
case AL_FREQUENCY_SHIFTER_RIGHT_DIRECTION:
if(auto diropt = DirectionFromEmum(val))
- props->Fshifter.RightDirection = *diropt;
+ props.RightDirection = *diropt;
else
throw effect_exception{AL_INVALID_VALUE,
"Unsupported frequency shifter right direction: 0x%04x", val};
@@ -84,33 +79,52 @@ void Fshifter_setParami(EffectProps *props, ALenum param, int val)
"Invalid frequency shifter integer property 0x%04x", param};
}
}
-void Fshifter_setParamiv(EffectProps *props, ALenum param, const int *vals)
-{ Fshifter_setParami(props, param, vals[0]); }
+void EffectHandler::SetParamiv(FshifterProps &props, ALenum param, const int *vals)
+{ SetParami(props, param, vals[0]); }
+
+void EffectHandler::SetParamf(FshifterProps &props, ALenum param, float val)
+{
+ switch(param)
+ {
+ case AL_FREQUENCY_SHIFTER_FREQUENCY:
+ if(!(val >= AL_FREQUENCY_SHIFTER_MIN_FREQUENCY && val <= AL_FREQUENCY_SHIFTER_MAX_FREQUENCY))
+ throw effect_exception{AL_INVALID_VALUE, "Frequency shifter frequency out of range"};
+ props.Frequency = val;
+ break;
+
+ default:
+ throw effect_exception{AL_INVALID_ENUM, "Invalid frequency shifter float property 0x%04x",
+ param};
+ }
+}
+void EffectHandler::SetParamfv(FshifterProps &props, ALenum param, const float *vals)
+{ SetParamf(props, param, vals[0]); }
-void Fshifter_getParami(const EffectProps *props, ALenum param, int *val)
+void EffectHandler::GetParami(const FshifterProps &props, ALenum param, int *val)
{
switch(param)
{
case AL_FREQUENCY_SHIFTER_LEFT_DIRECTION:
- *val = EnumFromDirection(props->Fshifter.LeftDirection);
+ *val = EnumFromDirection(props.LeftDirection);
break;
case AL_FREQUENCY_SHIFTER_RIGHT_DIRECTION:
- *val = EnumFromDirection(props->Fshifter.RightDirection);
+ *val = EnumFromDirection(props.RightDirection);
break;
+
default:
throw effect_exception{AL_INVALID_ENUM,
"Invalid frequency shifter integer property 0x%04x", param};
}
}
-void Fshifter_getParamiv(const EffectProps *props, ALenum param, int *vals)
-{ Fshifter_getParami(props, param, vals); }
+void EffectHandler::GetParamiv(const FshifterProps &props, ALenum param, int *vals)
+{ GetParami(props, param, vals); }
-void Fshifter_getParamf(const EffectProps *props, ALenum param, float *val)
+void EffectHandler::GetParamf(const FshifterProps &props, ALenum param, float *val)
{
switch(param)
{
case AL_FREQUENCY_SHIFTER_FREQUENCY:
- *val = props->Fshifter.Frequency;
+ *val = props.Frequency;
break;
default:
@@ -118,23 +132,9 @@ void Fshifter_getParamf(const EffectProps *props, ALenum param, float *val)
param};
}
}
-void Fshifter_getParamfv(const EffectProps *props, ALenum param, float *vals)
-{ Fshifter_getParamf(props, param, vals); }
+void EffectHandler::GetParamfv(const FshifterProps &props, ALenum param, float *vals)
+{ GetParamf(props, param, vals); }
-EffectProps genDefaultProps() noexcept
-{
- EffectProps props{};
- props.Fshifter.Frequency = AL_FREQUENCY_SHIFTER_DEFAULT_FREQUENCY;
- props.Fshifter.LeftDirection = *DirectionFromEmum(AL_FREQUENCY_SHIFTER_DEFAULT_LEFT_DIRECTION);
- props.Fshifter.RightDirection = *DirectionFromEmum(AL_FREQUENCY_SHIFTER_DEFAULT_RIGHT_DIRECTION);
- return props;
-}
-
-} // namespace
-
-DEFINE_ALEFFECT_VTABLE(Fshifter);
-
-const EffectProps FshifterEffectProps{genDefaultProps()};
#ifdef ALSOFT_EAX
namespace {
@@ -197,10 +197,9 @@ template<>
throw Exception{message};
}
-template<>
-bool FrequencyShifterCommitter::commit(const EaxEffectProps &props)
+bool EaxFrequencyShifterCommitter::commit(const EAXFREQUENCYSHIFTERPROPERTIES &props)
{
- if(props == mEaxProps)
+ if(auto *cur = std::get_if<EAXFREQUENCYSHIFTERPROPERTIES>(&mEaxProps); cur && *cur == props)
return false;
mEaxProps = props;
@@ -214,16 +213,18 @@ bool FrequencyShifterCommitter::commit(const EaxEffectProps &props)
return FShifterDirection::Off;
};
- auto &eaxprops = std::get<EAXFREQUENCYSHIFTERPROPERTIES>(props);
- mAlProps.Fshifter.Frequency = eaxprops.flFrequency;
- mAlProps.Fshifter.LeftDirection = get_direction(eaxprops.ulLeftDirection);
- mAlProps.Fshifter.RightDirection = get_direction(eaxprops.ulRightDirection);
+ mAlProps = [&]{
+ FshifterProps ret{};
+ ret.Frequency = props.flFrequency;
+ ret.LeftDirection = get_direction(props.ulLeftDirection);
+ ret.RightDirection = get_direction(props.ulRightDirection);
+ return ret;
+ }();
return true;
}
-template<>
-void FrequencyShifterCommitter::SetDefaults(EaxEffectProps &props)
+void EaxFrequencyShifterCommitter::SetDefaults(EaxEffectProps &props)
{
static constexpr EAXFREQUENCYSHIFTERPROPERTIES defprops{[]
{
@@ -236,10 +237,8 @@ void FrequencyShifterCommitter::SetDefaults(EaxEffectProps &props)
props = defprops;
}
-template<>
-void FrequencyShifterCommitter::Get(const EaxCall &call, const EaxEffectProps &props_)
+void EaxFrequencyShifterCommitter::Get(const EaxCall &call, const EAXFREQUENCYSHIFTERPROPERTIES &props)
{
- auto &props = std::get<EAXFREQUENCYSHIFTERPROPERTIES>(props_);
switch(call.get_property_id())
{
case EAXFREQUENCYSHIFTER_NONE: break;
@@ -251,10 +250,8 @@ void FrequencyShifterCommitter::Get(const EaxCall &call, const EaxEffectProps &p
}
}
-template<>
-void FrequencyShifterCommitter::Set(const EaxCall &call, EaxEffectProps &props_)
+void EaxFrequencyShifterCommitter::Set(const EaxCall &call, EAXFREQUENCYSHIFTERPROPERTIES &props)
{
- auto &props = std::get<EAXFREQUENCYSHIFTERPROPERTIES>(props_);
switch(call.get_property_id())
{
case EAXFREQUENCYSHIFTER_NONE: break;
diff --git a/al/effects/modulator.cpp b/al/effects/modulator.cpp
index 366e7ef7..7e9424c0 100644
--- a/al/effects/modulator.cpp
+++ b/al/effects/modulator.cpp
@@ -42,40 +42,31 @@ ALenum EnumFromWaveform(ModulatorWaveform type)
std::to_string(static_cast<int>(type))};
}
-void Modulator_setParamf(EffectProps *props, ALenum param, float val)
+EffectProps genDefaultProps() noexcept
{
- switch(param)
- {
- case AL_RING_MODULATOR_FREQUENCY:
- if(!(val >= AL_RING_MODULATOR_MIN_FREQUENCY && val <= AL_RING_MODULATOR_MAX_FREQUENCY))
- throw effect_exception{AL_INVALID_VALUE, "Modulator frequency out of range: %f", val};
- props->Modulator.Frequency = val;
- break;
+ ModulatorProps props{};
+ props.Frequency = AL_RING_MODULATOR_DEFAULT_FREQUENCY;
+ props.HighPassCutoff = AL_RING_MODULATOR_DEFAULT_HIGHPASS_CUTOFF;
+ props.Waveform = WaveformFromEmum(AL_RING_MODULATOR_DEFAULT_WAVEFORM).value();
+ return props;
+}
- case AL_RING_MODULATOR_HIGHPASS_CUTOFF:
- if(!(val >= AL_RING_MODULATOR_MIN_HIGHPASS_CUTOFF && val <= AL_RING_MODULATOR_MAX_HIGHPASS_CUTOFF))
- throw effect_exception{AL_INVALID_VALUE, "Modulator high-pass cutoff out of range: %f", val};
- props->Modulator.HighPassCutoff = val;
- break;
+} // namespace
- default:
- throw effect_exception{AL_INVALID_ENUM, "Invalid modulator float property 0x%04x", param};
- }
-}
-void Modulator_setParamfv(EffectProps *props, ALenum param, const float *vals)
-{ Modulator_setParamf(props, param, vals[0]); }
-void Modulator_setParami(EffectProps *props, ALenum param, int val)
+const EffectProps ModulatorEffectProps{genDefaultProps()};
+
+void EffectHandler::SetParami(ModulatorProps &props, ALenum param, int val)
{
switch(param)
{
case AL_RING_MODULATOR_FREQUENCY:
case AL_RING_MODULATOR_HIGHPASS_CUTOFF:
- Modulator_setParamf(props, param, static_cast<float>(val));
+ SetParamf(props, param, static_cast<float>(val));
break;
case AL_RING_MODULATOR_WAVEFORM:
if(auto formopt = WaveformFromEmum(val))
- props->Modulator.Waveform = *formopt;
+ props.Waveform = *formopt;
else
throw effect_exception{AL_INVALID_VALUE, "Invalid modulator waveform: 0x%04x", val};
break;
@@ -85,62 +76,61 @@ void Modulator_setParami(EffectProps *props, ALenum param, int val)
param};
}
}
-void Modulator_setParamiv(EffectProps *props, ALenum param, const int *vals)
-{ Modulator_setParami(props, param, vals[0]); }
+void EffectHandler::SetParamiv(ModulatorProps &props, ALenum param, const int *vals)
+{ SetParami(props, param, vals[0]); }
-void Modulator_getParami(const EffectProps *props, ALenum param, int *val)
+void EffectHandler::SetParamf(ModulatorProps &props, ALenum param, float val)
{
switch(param)
{
case AL_RING_MODULATOR_FREQUENCY:
- *val = static_cast<int>(props->Modulator.Frequency);
+ if(!(val >= AL_RING_MODULATOR_MIN_FREQUENCY && val <= AL_RING_MODULATOR_MAX_FREQUENCY))
+ throw effect_exception{AL_INVALID_VALUE, "Modulator frequency out of range: %f", val};
+ props.Frequency = val;
break;
+
case AL_RING_MODULATOR_HIGHPASS_CUTOFF:
- *val = static_cast<int>(props->Modulator.HighPassCutoff);
- break;
- case AL_RING_MODULATOR_WAVEFORM:
- *val = EnumFromWaveform(props->Modulator.Waveform);
+ if(!(val >= AL_RING_MODULATOR_MIN_HIGHPASS_CUTOFF && val <= AL_RING_MODULATOR_MAX_HIGHPASS_CUTOFF))
+ throw effect_exception{AL_INVALID_VALUE, "Modulator high-pass cutoff out of range: %f", val};
+ props.HighPassCutoff = val;
break;
default:
+ throw effect_exception{AL_INVALID_ENUM, "Invalid modulator float property 0x%04x", param};
+ }
+}
+void EffectHandler::SetParamfv(ModulatorProps &props, ALenum param, const float *vals)
+{ SetParamf(props, param, vals[0]); }
+
+void EffectHandler::GetParami(const ModulatorProps &props, ALenum param, int *val)
+{
+ switch(param)
+ {
+ case AL_RING_MODULATOR_FREQUENCY: *val = static_cast<int>(props.Frequency); break;
+ case AL_RING_MODULATOR_HIGHPASS_CUTOFF: *val = static_cast<int>(props.HighPassCutoff); break;
+ case AL_RING_MODULATOR_WAVEFORM: *val = EnumFromWaveform(props.Waveform); break;
+
+ default:
throw effect_exception{AL_INVALID_ENUM, "Invalid modulator integer property 0x%04x",
param};
}
}
-void Modulator_getParamiv(const EffectProps *props, ALenum param, int *vals)
-{ Modulator_getParami(props, param, vals); }
-void Modulator_getParamf(const EffectProps *props, ALenum param, float *val)
+void EffectHandler::GetParamiv(const ModulatorProps &props, ALenum param, int *vals)
+{ GetParami(props, param, vals); }
+void EffectHandler::GetParamf(const ModulatorProps &props, ALenum param, float *val)
{
switch(param)
{
- case AL_RING_MODULATOR_FREQUENCY:
- *val = props->Modulator.Frequency;
- break;
- case AL_RING_MODULATOR_HIGHPASS_CUTOFF:
- *val = props->Modulator.HighPassCutoff;
- break;
+ case AL_RING_MODULATOR_FREQUENCY: *val = props.Frequency; break;
+ case AL_RING_MODULATOR_HIGHPASS_CUTOFF: *val = props.HighPassCutoff; break;
default:
throw effect_exception{AL_INVALID_ENUM, "Invalid modulator float property 0x%04x", param};
}
}
-void Modulator_getParamfv(const EffectProps *props, ALenum param, float *vals)
-{ Modulator_getParamf(props, param, vals); }
+void EffectHandler::GetParamfv(const ModulatorProps &props, ALenum param, float *vals)
+{ GetParamf(props, param, vals); }
-EffectProps genDefaultProps() noexcept
-{
- EffectProps props{};
- props.Modulator.Frequency = AL_RING_MODULATOR_DEFAULT_FREQUENCY;
- props.Modulator.HighPassCutoff = AL_RING_MODULATOR_DEFAULT_HIGHPASS_CUTOFF;
- props.Modulator.Waveform = *WaveformFromEmum(AL_RING_MODULATOR_DEFAULT_WAVEFORM);
- return props;
-}
-
-} // namespace
-
-DEFINE_ALEFFECT_VTABLE(Modulator);
-
-const EffectProps ModulatorEffectProps{genDefaultProps()};
#ifdef ALSOFT_EAX
namespace {
@@ -203,10 +193,9 @@ template<>
throw Exception{message};
}
-template<>
-bool ModulatorCommitter::commit(const EaxEffectProps &props)
+bool EaxModulatorCommitter::commit(const EAXRINGMODULATORPROPERTIES &props)
{
- if(props == mEaxProps)
+ if(auto *cur = std::get_if<EAXRINGMODULATORPROPERTIES>(&mEaxProps); cur && *cur == props)
return false;
mEaxProps = props;
@@ -222,16 +211,18 @@ bool ModulatorCommitter::commit(const EaxEffectProps &props)
return ModulatorWaveform::Sinusoid;
};
- auto &eaxprops = std::get<EAXRINGMODULATORPROPERTIES>(props);
- mAlProps.Modulator.Frequency = eaxprops.flFrequency;
- mAlProps.Modulator.HighPassCutoff = eaxprops.flHighPassCutOff;
- mAlProps.Modulator.Waveform = get_waveform(eaxprops.ulWaveform);
+ mAlProps = [&]{
+ ModulatorProps ret{};
+ ret.Frequency = props.flFrequency;
+ ret.HighPassCutoff = props.flHighPassCutOff;
+ ret.Waveform = get_waveform(props.ulWaveform);
+ return ret;
+ }();
return true;
}
-template<>
-void ModulatorCommitter::SetDefaults(EaxEffectProps &props)
+void EaxModulatorCommitter::SetDefaults(EaxEffectProps &props)
{
static constexpr EAXRINGMODULATORPROPERTIES defprops{[]
{
@@ -244,10 +235,8 @@ void ModulatorCommitter::SetDefaults(EaxEffectProps &props)
props = defprops;
}
-template<>
-void ModulatorCommitter::Get(const EaxCall &call, const EaxEffectProps &props_)
+void EaxModulatorCommitter::Get(const EaxCall &call, const EAXRINGMODULATORPROPERTIES &props)
{
- auto &props = std::get<EAXRINGMODULATORPROPERTIES>(props_);
switch(call.get_property_id())
{
case EAXRINGMODULATOR_NONE: break;
@@ -259,11 +248,9 @@ void ModulatorCommitter::Get(const EaxCall &call, const EaxEffectProps &props_)
}
}
-template<>
-void ModulatorCommitter::Set(const EaxCall &call, EaxEffectProps &props_)
+void EaxModulatorCommitter::Set(const EaxCall &call, EAXRINGMODULATORPROPERTIES &props)
{
- auto &props = std::get<EAXRINGMODULATORPROPERTIES>(props_);
- switch (call.get_property_id())
+ switch(call.get_property_id())
{
case EAXRINGMODULATOR_NONE: break;
case EAXRINGMODULATOR_ALLPARAMETERS: defer<AllValidator>(call, props); break;
diff --git a/al/effects/null.cpp b/al/effects/null.cpp
index 1e8787e7..4b00ef4f 100644
--- a/al/effects/null.cpp
+++ b/al/effects/null.cpp
@@ -14,7 +14,17 @@
namespace {
-void Null_setParami(EffectProps* /*props*/, ALenum param, int /*val*/)
+EffectProps genDefaultProps() noexcept
+{
+ EffectProps props{};
+ return props;
+}
+
+} // namespace
+
+const EffectProps NullEffectProps{genDefaultProps()};
+
+void EffectHandler::SetParami(std::monostate& /*props*/, ALenum param, int /*val*/)
{
switch(param)
{
@@ -23,15 +33,15 @@ void Null_setParami(EffectProps* /*props*/, ALenum param, int /*val*/)
param};
}
}
-void Null_setParamiv(EffectProps *props, ALenum param, const int *vals)
+void EffectHandler::SetParamiv(std::monostate &props, ALenum param, const int *vals)
{
switch(param)
{
default:
- Null_setParami(props, param, vals[0]);
+ SetParami(props, param, vals[0]);
}
}
-void Null_setParamf(EffectProps* /*props*/, ALenum param, float /*val*/)
+void EffectHandler::SetParamf(std::monostate& /*props*/, ALenum param, float /*val*/)
{
switch(param)
{
@@ -40,16 +50,16 @@ void Null_setParamf(EffectProps* /*props*/, ALenum param, float /*val*/)
param};
}
}
-void Null_setParamfv(EffectProps *props, ALenum param, const float *vals)
+void EffectHandler::SetParamfv(std::monostate &props, ALenum param, const float *vals)
{
switch(param)
{
default:
- Null_setParamf(props, param, vals[0]);
+ SetParamf(props, param, vals[0]);
}
}
-void Null_getParami(const EffectProps* /*props*/, ALenum param, int* /*val*/)
+void EffectHandler::GetParami(const std::monostate& /*props*/, ALenum param, int* /*val*/)
{
switch(param)
{
@@ -58,15 +68,15 @@ void Null_getParami(const EffectProps* /*props*/, ALenum param, int* /*val*/)
param};
}
}
-void Null_getParamiv(const EffectProps *props, ALenum param, int *vals)
+void EffectHandler::GetParamiv(const std::monostate &props, ALenum param, int *vals)
{
switch(param)
{
default:
- Null_getParami(props, param, vals);
+ GetParami(props, param, vals);
}
}
-void Null_getParamf(const EffectProps* /*props*/, ALenum param, float* /*val*/)
+void EffectHandler::GetParamf(const std::monostate& /*props*/, ALenum param, float* /*val*/)
{
switch(param)
{
@@ -75,27 +85,15 @@ void Null_getParamf(const EffectProps* /*props*/, ALenum param, float* /*val*/)
param};
}
}
-void Null_getParamfv(const EffectProps *props, ALenum param, float *vals)
+void EffectHandler::GetParamfv(const std::monostate &props, ALenum param, float *vals)
{
switch(param)
{
default:
- Null_getParamf(props, param, vals);
+ GetParamf(props, param, vals);
}
}
-EffectProps genDefaultProps() noexcept
-{
- EffectProps props{};
- return props;
-}
-
-} // namespace
-
-DEFINE_ALEFFECT_VTABLE(Null);
-
-const EffectProps NullEffectProps{genDefaultProps()};
-
#ifdef ALSOFT_EAX
namespace {
@@ -117,29 +115,26 @@ template<>
throw Exception{message};
}
-template<>
-bool NullCommitter::commit(const EaxEffectProps &props)
+bool EaxNullCommitter::commit(const std::monostate &props)
{
- const bool ret{props != mEaxProps};
+ const bool ret{std::holds_alternative<std::monostate>(mEaxProps)};
mEaxProps = props;
+ mAlProps = std::monostate{};
return ret;
}
-template<>
-void NullCommitter::SetDefaults(EaxEffectProps &props)
+void EaxNullCommitter::SetDefaults(EaxEffectProps &props)
{
- props.emplace<std::monostate>();
+ props = std::monostate{};
}
-template<>
-void NullCommitter::Get(const EaxCall &call, const EaxEffectProps&)
+void EaxNullCommitter::Get(const EaxCall &call, const std::monostate&)
{
if(call.get_property_id() != 0)
fail_unknown_property_id();
}
-template<>
-void NullCommitter::Set(const EaxCall &call, EaxEffectProps&)
+void EaxNullCommitter::Set(const EaxCall &call, std::monostate&)
{
if(call.get_property_id() != 0)
fail_unknown_property_id();
diff --git a/al/effects/pshifter.cpp b/al/effects/pshifter.cpp
index 10824016..b36fe034 100644
--- a/al/effects/pshifter.cpp
+++ b/al/effects/pshifter.cpp
@@ -16,28 +16,32 @@
namespace {
-void Pshifter_setParamf(EffectProps*, ALenum param, float)
-{ throw effect_exception{AL_INVALID_ENUM, "Invalid pitch shifter float property 0x%04x", param}; }
-void Pshifter_setParamfv(EffectProps*, ALenum param, const float*)
+EffectProps genDefaultProps() noexcept
{
- throw effect_exception{AL_INVALID_ENUM, "Invalid pitch shifter float-vector property 0x%04x",
- param};
+ PshifterProps props{};
+ props.CoarseTune = AL_PITCH_SHIFTER_DEFAULT_COARSE_TUNE;
+ props.FineTune = AL_PITCH_SHIFTER_DEFAULT_FINE_TUNE;
+ return props;
}
-void Pshifter_setParami(EffectProps *props, ALenum param, int val)
+} // namespace
+
+const EffectProps PshifterEffectProps{genDefaultProps()};
+
+void EffectHandler::SetParami(PshifterProps &props, ALenum param, int val)
{
switch(param)
{
case AL_PITCH_SHIFTER_COARSE_TUNE:
if(!(val >= AL_PITCH_SHIFTER_MIN_COARSE_TUNE && val <= AL_PITCH_SHIFTER_MAX_COARSE_TUNE))
throw effect_exception{AL_INVALID_VALUE, "Pitch shifter coarse tune out of range"};
- props->Pshifter.CoarseTune = val;
+ props.CoarseTune = val;
break;
case AL_PITCH_SHIFTER_FINE_TUNE:
if(!(val >= AL_PITCH_SHIFTER_MIN_FINE_TUNE && val <= AL_PITCH_SHIFTER_MAX_FINE_TUNE))
throw effect_exception{AL_INVALID_VALUE, "Pitch shifter fine tune out of range"};
- props->Pshifter.FineTune = val;
+ props.FineTune = val;
break;
default:
@@ -45,49 +49,40 @@ void Pshifter_setParami(EffectProps *props, ALenum param, int val)
param};
}
}
-void Pshifter_setParamiv(EffectProps *props, ALenum param, const int *vals)
-{ Pshifter_setParami(props, param, vals[0]); }
+void EffectHandler::SetParamiv(PshifterProps &props, ALenum param, const int *vals)
+{ SetParami(props, param, vals[0]); }
-void Pshifter_getParami(const EffectProps *props, ALenum param, int *val)
+void EffectHandler::SetParamf(PshifterProps&, ALenum param, float)
+{ throw effect_exception{AL_INVALID_ENUM, "Invalid pitch shifter float property 0x%04x", param}; }
+void EffectHandler::SetParamfv(PshifterProps&, ALenum param, const float*)
+{
+ throw effect_exception{AL_INVALID_ENUM, "Invalid pitch shifter float-vector property 0x%04x",
+ param};
+}
+
+void EffectHandler::GetParami(const PshifterProps &props, ALenum param, int *val)
{
switch(param)
{
- case AL_PITCH_SHIFTER_COARSE_TUNE:
- *val = props->Pshifter.CoarseTune;
- break;
- case AL_PITCH_SHIFTER_FINE_TUNE:
- *val = props->Pshifter.FineTune;
- break;
+ case AL_PITCH_SHIFTER_COARSE_TUNE: *val = props.CoarseTune; break;
+ case AL_PITCH_SHIFTER_FINE_TUNE: *val = props.FineTune; break;
default:
throw effect_exception{AL_INVALID_ENUM, "Invalid pitch shifter integer property 0x%04x",
param};
}
}
-void Pshifter_getParamiv(const EffectProps *props, ALenum param, int *vals)
-{ Pshifter_getParami(props, param, vals); }
+void EffectHandler::GetParamiv(const PshifterProps &props, ALenum param, int *vals)
+{ GetParami(props, param, vals); }
-void Pshifter_getParamf(const EffectProps*, ALenum param, float*)
+void EffectHandler::GetParamf(const PshifterProps&, ALenum param, float*)
{ throw effect_exception{AL_INVALID_ENUM, "Invalid pitch shifter float property 0x%04x", param}; }
-void Pshifter_getParamfv(const EffectProps*, ALenum param, float*)
+void EffectHandler::GetParamfv(const PshifterProps&, ALenum param, float*)
{
throw effect_exception{AL_INVALID_ENUM, "Invalid pitch shifter float vector-property 0x%04x",
param};
}
-EffectProps genDefaultProps() noexcept
-{
- EffectProps props{};
- props.Pshifter.CoarseTune = AL_PITCH_SHIFTER_DEFAULT_COARSE_TUNE;
- props.Pshifter.FineTune = AL_PITCH_SHIFTER_DEFAULT_FINE_TUNE;
- return props;
-}
-
-} // namespace
-
-DEFINE_ALEFFECT_VTABLE(Pshifter);
-
-const EffectProps PshifterEffectProps{genDefaultProps()};
#ifdef ALSOFT_EAX
namespace {
@@ -138,32 +133,30 @@ template<>
throw Exception{message};
}
-template<>
-bool PitchShifterCommitter::commit(const EaxEffectProps &props)
+bool EaxPitchShifterCommitter::commit(const EAXPITCHSHIFTERPROPERTIES &props)
{
- if(props == mEaxProps)
+ if(auto *cur = std::get_if<EAXPITCHSHIFTERPROPERTIES>(&mEaxProps); cur && *cur == props)
return false;
mEaxProps = props;
-
- auto &eaxprops = std::get<EAXPITCHSHIFTERPROPERTIES>(props);
- mAlProps.Pshifter.CoarseTune = static_cast<int>(eaxprops.lCoarseTune);
- mAlProps.Pshifter.FineTune = static_cast<int>(eaxprops.lFineTune);
+ mAlProps = [&]{
+ PshifterProps ret{};
+ ret.CoarseTune = static_cast<int>(props.lCoarseTune);
+ ret.FineTune = static_cast<int>(props.lFineTune);
+ return ret;
+ }();
return true;
}
-template<>
-void PitchShifterCommitter::SetDefaults(EaxEffectProps &props)
+void EaxPitchShifterCommitter::SetDefaults(EaxEffectProps &props)
{
props = EAXPITCHSHIFTERPROPERTIES{EAXPITCHSHIFTER_DEFAULTCOARSETUNE,
EAXPITCHSHIFTER_DEFAULTFINETUNE};
}
-template<>
-void PitchShifterCommitter::Get(const EaxCall &call, const EaxEffectProps &props_)
+void EaxPitchShifterCommitter::Get(const EaxCall &call, const EAXPITCHSHIFTERPROPERTIES &props)
{
- auto &props = std::get<EAXPITCHSHIFTERPROPERTIES>(props_);
switch(call.get_property_id())
{
case EAXPITCHSHIFTER_NONE: break;
@@ -174,10 +167,8 @@ void PitchShifterCommitter::Get(const EaxCall &call, const EaxEffectProps &props
}
}
-template<>
-void PitchShifterCommitter::Set(const EaxCall &call, EaxEffectProps &props_)
+void EaxPitchShifterCommitter::Set(const EaxCall &call, EAXPITCHSHIFTERPROPERTIES &props)
{
- auto &props = std::get<EAXPITCHSHIFTERPROPERTIES>(props_);
switch(call.get_property_id())
{
case EAXPITCHSHIFTER_NONE: break;
diff --git a/al/effects/reverb.cpp b/al/effects/reverb.cpp
index b037443f..f0df51b2 100644
--- a/al/effects/reverb.cpp
+++ b/al/effects/reverb.cpp
@@ -20,14 +20,80 @@
namespace {
-void Reverb_setParami(EffectProps *props, ALenum param, int val)
+EffectProps genDefaultProps() noexcept
+{
+ ReverbProps props{};
+ props.Density = AL_EAXREVERB_DEFAULT_DENSITY;
+ props.Diffusion = AL_EAXREVERB_DEFAULT_DIFFUSION;
+ props.Gain = AL_EAXREVERB_DEFAULT_GAIN;
+ props.GainHF = AL_EAXREVERB_DEFAULT_GAINHF;
+ props.GainLF = AL_EAXREVERB_DEFAULT_GAINLF;
+ props.DecayTime = AL_EAXREVERB_DEFAULT_DECAY_TIME;
+ props.DecayHFRatio = AL_EAXREVERB_DEFAULT_DECAY_HFRATIO;
+ props.DecayLFRatio = AL_EAXREVERB_DEFAULT_DECAY_LFRATIO;
+ props.ReflectionsGain = AL_EAXREVERB_DEFAULT_REFLECTIONS_GAIN;
+ props.ReflectionsDelay = AL_EAXREVERB_DEFAULT_REFLECTIONS_DELAY;
+ props.ReflectionsPan[0] = AL_EAXREVERB_DEFAULT_REFLECTIONS_PAN_XYZ;
+ props.ReflectionsPan[1] = AL_EAXREVERB_DEFAULT_REFLECTIONS_PAN_XYZ;
+ props.ReflectionsPan[2] = AL_EAXREVERB_DEFAULT_REFLECTIONS_PAN_XYZ;
+ props.LateReverbGain = AL_EAXREVERB_DEFAULT_LATE_REVERB_GAIN;
+ props.LateReverbDelay = AL_EAXREVERB_DEFAULT_LATE_REVERB_DELAY;
+ props.LateReverbPan[0] = AL_EAXREVERB_DEFAULT_LATE_REVERB_PAN_XYZ;
+ props.LateReverbPan[1] = AL_EAXREVERB_DEFAULT_LATE_REVERB_PAN_XYZ;
+ props.LateReverbPan[2] = AL_EAXREVERB_DEFAULT_LATE_REVERB_PAN_XYZ;
+ props.EchoTime = AL_EAXREVERB_DEFAULT_ECHO_TIME;
+ props.EchoDepth = AL_EAXREVERB_DEFAULT_ECHO_DEPTH;
+ props.ModulationTime = AL_EAXREVERB_DEFAULT_MODULATION_TIME;
+ props.ModulationDepth = AL_EAXREVERB_DEFAULT_MODULATION_DEPTH;
+ props.AirAbsorptionGainHF = AL_EAXREVERB_DEFAULT_AIR_ABSORPTION_GAINHF;
+ props.HFReference = AL_EAXREVERB_DEFAULT_HFREFERENCE;
+ props.LFReference = AL_EAXREVERB_DEFAULT_LFREFERENCE;
+ props.RoomRolloffFactor = AL_EAXREVERB_DEFAULT_ROOM_ROLLOFF_FACTOR;
+ props.DecayHFLimit = AL_EAXREVERB_DEFAULT_DECAY_HFLIMIT;
+ return props;
+}
+
+EffectProps genDefaultStdProps() noexcept
+{
+ ReverbProps props{};
+ props.Density = AL_REVERB_DEFAULT_DENSITY;
+ props.Diffusion = AL_REVERB_DEFAULT_DIFFUSION;
+ props.Gain = AL_REVERB_DEFAULT_GAIN;
+ props.GainHF = AL_REVERB_DEFAULT_GAINHF;
+ props.GainLF = 1.0f;
+ props.DecayTime = AL_REVERB_DEFAULT_DECAY_TIME;
+ props.DecayHFRatio = AL_REVERB_DEFAULT_DECAY_HFRATIO;
+ props.DecayLFRatio = 1.0f;
+ props.ReflectionsGain = AL_REVERB_DEFAULT_REFLECTIONS_GAIN;
+ props.ReflectionsDelay = AL_REVERB_DEFAULT_REFLECTIONS_DELAY;
+ props.ReflectionsPan = {0.0f, 0.0f, 0.0f};
+ props.LateReverbGain = AL_REVERB_DEFAULT_LATE_REVERB_GAIN;
+ props.LateReverbDelay = AL_REVERB_DEFAULT_LATE_REVERB_DELAY;
+ props.LateReverbPan = {0.0f, 0.0f, 0.0f};
+ props.EchoTime = 0.25f;
+ props.EchoDepth = 0.0f;
+ props.ModulationTime = 0.25f;
+ props.ModulationDepth = 0.0f;
+ props.AirAbsorptionGainHF = AL_REVERB_DEFAULT_AIR_ABSORPTION_GAINHF;
+ props.HFReference = 5000.0f;
+ props.LFReference = 250.0f;
+ props.RoomRolloffFactor = AL_REVERB_DEFAULT_ROOM_ROLLOFF_FACTOR;
+ props.DecayHFLimit = AL_REVERB_DEFAULT_DECAY_HFLIMIT;
+ return props;
+}
+
+} // namespace
+
+const EffectProps ReverbEffectProps{genDefaultProps()};
+
+void EffectHandler::SetParami(ReverbProps &props, ALenum param, int val)
{
switch(param)
{
case AL_EAXREVERB_DECAY_HFLIMIT:
if(!(val >= AL_EAXREVERB_MIN_DECAY_HFLIMIT && val <= AL_EAXREVERB_MAX_DECAY_HFLIMIT))
throw effect_exception{AL_INVALID_VALUE, "EAX Reverb decay hflimit out of range"};
- props->Reverb.DecayHFLimit = val != AL_FALSE;
+ props.DecayHFLimit = val != AL_FALSE;
break;
default:
@@ -35,167 +101,167 @@ void Reverb_setParami(EffectProps *props, ALenum param, int val)
param};
}
}
-void Reverb_setParamiv(EffectProps *props, ALenum param, const int *vals)
-{ Reverb_setParami(props, param, vals[0]); }
-void Reverb_setParamf(EffectProps *props, ALenum param, float val)
+void EffectHandler::SetParamiv(ReverbProps &props, ALenum param, const int *vals)
+{ SetParami(props, param, vals[0]); }
+void EffectHandler::SetParamf(ReverbProps &props, ALenum param, float val)
{
switch(param)
{
case AL_EAXREVERB_DENSITY:
if(!(val >= AL_EAXREVERB_MIN_DENSITY && val <= AL_EAXREVERB_MAX_DENSITY))
throw effect_exception{AL_INVALID_VALUE, "EAX Reverb density out of range"};
- props->Reverb.Density = val;
+ props.Density = val;
break;
case AL_EAXREVERB_DIFFUSION:
if(!(val >= AL_EAXREVERB_MIN_DIFFUSION && val <= AL_EAXREVERB_MAX_DIFFUSION))
throw effect_exception{AL_INVALID_VALUE, "EAX Reverb diffusion out of range"};
- props->Reverb.Diffusion = val;
+ props.Diffusion = val;
break;
case AL_EAXREVERB_GAIN:
if(!(val >= AL_EAXREVERB_MIN_GAIN && val <= AL_EAXREVERB_MAX_GAIN))
throw effect_exception{AL_INVALID_VALUE, "EAX Reverb gain out of range"};
- props->Reverb.Gain = val;
+ props.Gain = val;
break;
case AL_EAXREVERB_GAINHF:
if(!(val >= AL_EAXREVERB_MIN_GAINHF && val <= AL_EAXREVERB_MAX_GAINHF))
throw effect_exception{AL_INVALID_VALUE, "EAX Reverb gainhf out of range"};
- props->Reverb.GainHF = val;
+ props.GainHF = val;
break;
case AL_EAXREVERB_GAINLF:
if(!(val >= AL_EAXREVERB_MIN_GAINLF && val <= AL_EAXREVERB_MAX_GAINLF))
throw effect_exception{AL_INVALID_VALUE, "EAX Reverb gainlf out of range"};
- props->Reverb.GainLF = val;
+ props.GainLF = val;
break;
case AL_EAXREVERB_DECAY_TIME:
if(!(val >= AL_EAXREVERB_MIN_DECAY_TIME && val <= AL_EAXREVERB_MAX_DECAY_TIME))
throw effect_exception{AL_INVALID_VALUE, "EAX Reverb decay time out of range"};
- props->Reverb.DecayTime = val;
+ props.DecayTime = val;
break;
case AL_EAXREVERB_DECAY_HFRATIO:
if(!(val >= AL_EAXREVERB_MIN_DECAY_HFRATIO && val <= AL_EAXREVERB_MAX_DECAY_HFRATIO))
throw effect_exception{AL_INVALID_VALUE, "EAX Reverb decay hfratio out of range"};
- props->Reverb.DecayHFRatio = val;
+ props.DecayHFRatio = val;
break;
case AL_EAXREVERB_DECAY_LFRATIO:
if(!(val >= AL_EAXREVERB_MIN_DECAY_LFRATIO && val <= AL_EAXREVERB_MAX_DECAY_LFRATIO))
throw effect_exception{AL_INVALID_VALUE, "EAX Reverb decay lfratio out of range"};
- props->Reverb.DecayLFRatio = val;
+ props.DecayLFRatio = val;
break;
case AL_EAXREVERB_REFLECTIONS_GAIN:
if(!(val >= AL_EAXREVERB_MIN_REFLECTIONS_GAIN && val <= AL_EAXREVERB_MAX_REFLECTIONS_GAIN))
throw effect_exception{AL_INVALID_VALUE, "EAX Reverb reflections gain out of range"};
- props->Reverb.ReflectionsGain = val;
+ props.ReflectionsGain = val;
break;
case AL_EAXREVERB_REFLECTIONS_DELAY:
if(!(val >= AL_EAXREVERB_MIN_REFLECTIONS_DELAY && val <= AL_EAXREVERB_MAX_REFLECTIONS_DELAY))
throw effect_exception{AL_INVALID_VALUE, "EAX Reverb reflections delay out of range"};
- props->Reverb.ReflectionsDelay = val;
+ props.ReflectionsDelay = val;
break;
case AL_EAXREVERB_LATE_REVERB_GAIN:
if(!(val >= AL_EAXREVERB_MIN_LATE_REVERB_GAIN && val <= AL_EAXREVERB_MAX_LATE_REVERB_GAIN))
throw effect_exception{AL_INVALID_VALUE, "EAX Reverb late reverb gain out of range"};
- props->Reverb.LateReverbGain = val;
+ props.LateReverbGain = val;
break;
case AL_EAXREVERB_LATE_REVERB_DELAY:
if(!(val >= AL_EAXREVERB_MIN_LATE_REVERB_DELAY && val <= AL_EAXREVERB_MAX_LATE_REVERB_DELAY))
throw effect_exception{AL_INVALID_VALUE, "EAX Reverb late reverb delay out of range"};
- props->Reverb.LateReverbDelay = val;
+ props.LateReverbDelay = val;
break;
case AL_EAXREVERB_ECHO_TIME:
if(!(val >= AL_EAXREVERB_MIN_ECHO_TIME && val <= AL_EAXREVERB_MAX_ECHO_TIME))
throw effect_exception{AL_INVALID_VALUE, "EAX Reverb echo time out of range"};
- props->Reverb.EchoTime = val;
+ props.EchoTime = val;
break;
case AL_EAXREVERB_ECHO_DEPTH:
if(!(val >= AL_EAXREVERB_MIN_ECHO_DEPTH && val <= AL_EAXREVERB_MAX_ECHO_DEPTH))
throw effect_exception{AL_INVALID_VALUE, "EAX Reverb echo depth out of range"};
- props->Reverb.EchoDepth = val;
+ props.EchoDepth = val;
break;
case AL_EAXREVERB_MODULATION_TIME:
if(!(val >= AL_EAXREVERB_MIN_MODULATION_TIME && val <= AL_EAXREVERB_MAX_MODULATION_TIME))
throw effect_exception{AL_INVALID_VALUE, "EAX Reverb modulation time out of range"};
- props->Reverb.ModulationTime = val;
+ props.ModulationTime = val;
break;
case AL_EAXREVERB_MODULATION_DEPTH:
if(!(val >= AL_EAXREVERB_MIN_MODULATION_DEPTH && val <= AL_EAXREVERB_MAX_MODULATION_DEPTH))
throw effect_exception{AL_INVALID_VALUE, "EAX Reverb modulation depth out of range"};
- props->Reverb.ModulationDepth = val;
+ props.ModulationDepth = val;
break;
case AL_EAXREVERB_AIR_ABSORPTION_GAINHF:
if(!(val >= AL_EAXREVERB_MIN_AIR_ABSORPTION_GAINHF && val <= AL_EAXREVERB_MAX_AIR_ABSORPTION_GAINHF))
throw effect_exception{AL_INVALID_VALUE, "EAX Reverb air absorption gainhf out of range"};
- props->Reverb.AirAbsorptionGainHF = val;
+ props.AirAbsorptionGainHF = val;
break;
case AL_EAXREVERB_HFREFERENCE:
if(!(val >= AL_EAXREVERB_MIN_HFREFERENCE && val <= AL_EAXREVERB_MAX_HFREFERENCE))
throw effect_exception{AL_INVALID_VALUE, "EAX Reverb hfreference out of range"};
- props->Reverb.HFReference = val;
+ props.HFReference = val;
break;
case AL_EAXREVERB_LFREFERENCE:
if(!(val >= AL_EAXREVERB_MIN_LFREFERENCE && val <= AL_EAXREVERB_MAX_LFREFERENCE))
throw effect_exception{AL_INVALID_VALUE, "EAX Reverb lfreference out of range"};
- props->Reverb.LFReference = val;
+ props.LFReference = val;
break;
case AL_EAXREVERB_ROOM_ROLLOFF_FACTOR:
if(!(val >= AL_EAXREVERB_MIN_ROOM_ROLLOFF_FACTOR && val <= AL_EAXREVERB_MAX_ROOM_ROLLOFF_FACTOR))
throw effect_exception{AL_INVALID_VALUE, "EAX Reverb room rolloff factor out of range"};
- props->Reverb.RoomRolloffFactor = val;
+ props.RoomRolloffFactor = val;
break;
default:
throw effect_exception{AL_INVALID_ENUM, "Invalid EAX reverb float property 0x%04x", param};
}
}
-void Reverb_setParamfv(EffectProps *props, ALenum param, const float *vals)
+void EffectHandler::SetParamfv(ReverbProps &props, ALenum param, const float *vals)
{
switch(param)
{
case AL_EAXREVERB_REFLECTIONS_PAN:
if(!(std::isfinite(vals[0]) && std::isfinite(vals[1]) && std::isfinite(vals[2])))
throw effect_exception{AL_INVALID_VALUE, "EAX Reverb reflections pan out of range"};
- props->Reverb.ReflectionsPan[0] = vals[0];
- props->Reverb.ReflectionsPan[1] = vals[1];
- props->Reverb.ReflectionsPan[2] = vals[2];
+ props.ReflectionsPan[0] = vals[0];
+ props.ReflectionsPan[1] = vals[1];
+ props.ReflectionsPan[2] = vals[2];
break;
case AL_EAXREVERB_LATE_REVERB_PAN:
if(!(std::isfinite(vals[0]) && std::isfinite(vals[1]) && std::isfinite(vals[2])))
throw effect_exception{AL_INVALID_VALUE, "EAX Reverb late reverb pan out of range"};
- props->Reverb.LateReverbPan[0] = vals[0];
- props->Reverb.LateReverbPan[1] = vals[1];
- props->Reverb.LateReverbPan[2] = vals[2];
+ props.LateReverbPan[0] = vals[0];
+ props.LateReverbPan[1] = vals[1];
+ props.LateReverbPan[2] = vals[2];
break;
default:
- Reverb_setParamf(props, param, vals[0]);
+ SetParamf(props, param, vals[0]);
break;
}
}
-void Reverb_getParami(const EffectProps *props, ALenum param, int *val)
+void EffectHandler::GetParami(const ReverbProps &props, ALenum param, int *val)
{
switch(param)
{
case AL_EAXREVERB_DECAY_HFLIMIT:
- *val = props->Reverb.DecayHFLimit;
+ *val = props.DecayHFLimit;
break;
default:
@@ -203,365 +269,214 @@ void Reverb_getParami(const EffectProps *props, ALenum param, int *val)
param};
}
}
-void Reverb_getParamiv(const EffectProps *props, ALenum param, int *vals)
-{ Reverb_getParami(props, param, vals); }
-void Reverb_getParamf(const EffectProps *props, ALenum param, float *val)
+void EffectHandler::GetParamiv(const ReverbProps &props, ALenum param, int *vals)
+{ GetParami(props, param, vals); }
+void EffectHandler::GetParamf(const ReverbProps &props, ALenum param, float *val)
{
switch(param)
{
- case AL_EAXREVERB_DENSITY:
- *val = props->Reverb.Density;
- break;
-
- case AL_EAXREVERB_DIFFUSION:
- *val = props->Reverb.Diffusion;
- break;
-
- case AL_EAXREVERB_GAIN:
- *val = props->Reverb.Gain;
- break;
-
- case AL_EAXREVERB_GAINHF:
- *val = props->Reverb.GainHF;
- break;
-
- case AL_EAXREVERB_GAINLF:
- *val = props->Reverb.GainLF;
- break;
-
- case AL_EAXREVERB_DECAY_TIME:
- *val = props->Reverb.DecayTime;
- break;
-
- case AL_EAXREVERB_DECAY_HFRATIO:
- *val = props->Reverb.DecayHFRatio;
- break;
-
- case AL_EAXREVERB_DECAY_LFRATIO:
- *val = props->Reverb.DecayLFRatio;
- break;
-
- case AL_EAXREVERB_REFLECTIONS_GAIN:
- *val = props->Reverb.ReflectionsGain;
- break;
-
- case AL_EAXREVERB_REFLECTIONS_DELAY:
- *val = props->Reverb.ReflectionsDelay;
- break;
-
- case AL_EAXREVERB_LATE_REVERB_GAIN:
- *val = props->Reverb.LateReverbGain;
- break;
-
- case AL_EAXREVERB_LATE_REVERB_DELAY:
- *val = props->Reverb.LateReverbDelay;
- break;
-
- case AL_EAXREVERB_ECHO_TIME:
- *val = props->Reverb.EchoTime;
- break;
-
- case AL_EAXREVERB_ECHO_DEPTH:
- *val = props->Reverb.EchoDepth;
- break;
-
- case AL_EAXREVERB_MODULATION_TIME:
- *val = props->Reverb.ModulationTime;
- break;
-
- case AL_EAXREVERB_MODULATION_DEPTH:
- *val = props->Reverb.ModulationDepth;
- break;
-
- case AL_EAXREVERB_AIR_ABSORPTION_GAINHF:
- *val = props->Reverb.AirAbsorptionGainHF;
- break;
-
- case AL_EAXREVERB_HFREFERENCE:
- *val = props->Reverb.HFReference;
- break;
-
- case AL_EAXREVERB_LFREFERENCE:
- *val = props->Reverb.LFReference;
- break;
-
- case AL_EAXREVERB_ROOM_ROLLOFF_FACTOR:
- *val = props->Reverb.RoomRolloffFactor;
- break;
+ case AL_EAXREVERB_DENSITY: *val = props.Density; break;
+ case AL_EAXREVERB_DIFFUSION: *val = props.Diffusion; break;
+ case AL_EAXREVERB_GAIN: *val = props.Gain; break;
+ case AL_EAXREVERB_GAINHF: *val = props.GainHF; break;
+ case AL_EAXREVERB_GAINLF: *val = props.GainLF; break;
+ case AL_EAXREVERB_DECAY_TIME: *val = props.DecayTime; break;
+ case AL_EAXREVERB_DECAY_HFRATIO: *val = props.DecayHFRatio; break;
+ case AL_EAXREVERB_DECAY_LFRATIO: *val = props.DecayLFRatio; break;
+ case AL_EAXREVERB_REFLECTIONS_GAIN: *val = props.ReflectionsGain; break;
+ case AL_EAXREVERB_REFLECTIONS_DELAY: *val = props.ReflectionsDelay; break;
+ case AL_EAXREVERB_LATE_REVERB_GAIN: *val = props.LateReverbGain; break;
+ case AL_EAXREVERB_LATE_REVERB_DELAY: *val = props.LateReverbDelay; break;
+ case AL_EAXREVERB_ECHO_TIME: *val = props.EchoTime; break;
+ case AL_EAXREVERB_ECHO_DEPTH: *val = props.EchoDepth; break;
+ case AL_EAXREVERB_MODULATION_TIME: *val = props.ModulationTime; break;
+ case AL_EAXREVERB_MODULATION_DEPTH: *val = props.ModulationDepth; break;
+ case AL_EAXREVERB_AIR_ABSORPTION_GAINHF: *val = props.AirAbsorptionGainHF; break;
+ case AL_EAXREVERB_HFREFERENCE: *val = props.HFReference; break;
+ case AL_EAXREVERB_LFREFERENCE: *val = props.LFReference; break;
+ case AL_EAXREVERB_ROOM_ROLLOFF_FACTOR: *val = props.RoomRolloffFactor; break;
default:
throw effect_exception{AL_INVALID_ENUM, "Invalid EAX reverb float property 0x%04x", param};
}
}
-void Reverb_getParamfv(const EffectProps *props, ALenum param, float *vals)
+void EffectHandler::GetParamfv(const ReverbProps &props, ALenum param, float *vals)
{
switch(param)
{
case AL_EAXREVERB_REFLECTIONS_PAN:
- vals[0] = props->Reverb.ReflectionsPan[0];
- vals[1] = props->Reverb.ReflectionsPan[1];
- vals[2] = props->Reverb.ReflectionsPan[2];
+ vals[0] = props.ReflectionsPan[0];
+ vals[1] = props.ReflectionsPan[1];
+ vals[2] = props.ReflectionsPan[2];
break;
case AL_EAXREVERB_LATE_REVERB_PAN:
- vals[0] = props->Reverb.LateReverbPan[0];
- vals[1] = props->Reverb.LateReverbPan[1];
- vals[2] = props->Reverb.LateReverbPan[2];
+ vals[0] = props.LateReverbPan[0];
+ vals[1] = props.LateReverbPan[1];
+ vals[2] = props.LateReverbPan[2];
break;
default:
- Reverb_getParamf(props, param, vals);
+ GetParamf(props, param, vals);
break;
}
}
-EffectProps genDefaultProps() noexcept
-{
- EffectProps props{};
- props.Reverb.Density = AL_EAXREVERB_DEFAULT_DENSITY;
- props.Reverb.Diffusion = AL_EAXREVERB_DEFAULT_DIFFUSION;
- props.Reverb.Gain = AL_EAXREVERB_DEFAULT_GAIN;
- props.Reverb.GainHF = AL_EAXREVERB_DEFAULT_GAINHF;
- props.Reverb.GainLF = AL_EAXREVERB_DEFAULT_GAINLF;
- props.Reverb.DecayTime = AL_EAXREVERB_DEFAULT_DECAY_TIME;
- props.Reverb.DecayHFRatio = AL_EAXREVERB_DEFAULT_DECAY_HFRATIO;
- props.Reverb.DecayLFRatio = AL_EAXREVERB_DEFAULT_DECAY_LFRATIO;
- props.Reverb.ReflectionsGain = AL_EAXREVERB_DEFAULT_REFLECTIONS_GAIN;
- props.Reverb.ReflectionsDelay = AL_EAXREVERB_DEFAULT_REFLECTIONS_DELAY;
- props.Reverb.ReflectionsPan[0] = AL_EAXREVERB_DEFAULT_REFLECTIONS_PAN_XYZ;
- props.Reverb.ReflectionsPan[1] = AL_EAXREVERB_DEFAULT_REFLECTIONS_PAN_XYZ;
- props.Reverb.ReflectionsPan[2] = AL_EAXREVERB_DEFAULT_REFLECTIONS_PAN_XYZ;
- props.Reverb.LateReverbGain = AL_EAXREVERB_DEFAULT_LATE_REVERB_GAIN;
- props.Reverb.LateReverbDelay = AL_EAXREVERB_DEFAULT_LATE_REVERB_DELAY;
- props.Reverb.LateReverbPan[0] = AL_EAXREVERB_DEFAULT_LATE_REVERB_PAN_XYZ;
- props.Reverb.LateReverbPan[1] = AL_EAXREVERB_DEFAULT_LATE_REVERB_PAN_XYZ;
- props.Reverb.LateReverbPan[2] = AL_EAXREVERB_DEFAULT_LATE_REVERB_PAN_XYZ;
- props.Reverb.EchoTime = AL_EAXREVERB_DEFAULT_ECHO_TIME;
- props.Reverb.EchoDepth = AL_EAXREVERB_DEFAULT_ECHO_DEPTH;
- props.Reverb.ModulationTime = AL_EAXREVERB_DEFAULT_MODULATION_TIME;
- props.Reverb.ModulationDepth = AL_EAXREVERB_DEFAULT_MODULATION_DEPTH;
- props.Reverb.AirAbsorptionGainHF = AL_EAXREVERB_DEFAULT_AIR_ABSORPTION_GAINHF;
- props.Reverb.HFReference = AL_EAXREVERB_DEFAULT_HFREFERENCE;
- props.Reverb.LFReference = AL_EAXREVERB_DEFAULT_LFREFERENCE;
- props.Reverb.RoomRolloffFactor = AL_EAXREVERB_DEFAULT_ROOM_ROLLOFF_FACTOR;
- props.Reverb.DecayHFLimit = AL_EAXREVERB_DEFAULT_DECAY_HFLIMIT;
- return props;
-}
+const EffectProps StdReverbEffectProps{genDefaultStdProps()};
-void StdReverb_setParami(EffectProps *props, ALenum param, int val)
+void EffectHandler::StdReverbSetParami(ReverbProps &props, ALenum param, int val)
{
switch(param)
{
case AL_REVERB_DECAY_HFLIMIT:
if(!(val >= AL_REVERB_MIN_DECAY_HFLIMIT && val <= AL_REVERB_MAX_DECAY_HFLIMIT))
- throw effect_exception{AL_INVALID_VALUE, "Reverb decay hflimit out of range"};
- props->Reverb.DecayHFLimit = val != AL_FALSE;
+ throw effect_exception{AL_INVALID_VALUE, "EAX Reverb decay hflimit out of range"};
+ props.DecayHFLimit = val != AL_FALSE;
break;
default:
- throw effect_exception{AL_INVALID_ENUM, "Invalid reverb integer property 0x%04x", param};
+ throw effect_exception{AL_INVALID_ENUM, "Invalid EAX reverb integer property 0x%04x",
+ param};
}
}
-void StdReverb_setParamiv(EffectProps *props, ALenum param, const int *vals)
-{ StdReverb_setParami(props, param, vals[0]); }
-void StdReverb_setParamf(EffectProps *props, ALenum param, float val)
+void EffectHandler::StdReverbSetParamiv(ReverbProps &props, ALenum param, const int *vals)
+{ StdReverbSetParami(props, param, vals[0]); }
+void EffectHandler::StdReverbSetParamf(ReverbProps &props, ALenum param, float val)
{
switch(param)
{
case AL_REVERB_DENSITY:
if(!(val >= AL_REVERB_MIN_DENSITY && val <= AL_REVERB_MAX_DENSITY))
- throw effect_exception{AL_INVALID_VALUE, "Reverb density out of range"};
- props->Reverb.Density = val;
+ throw effect_exception{AL_INVALID_VALUE, "EAX Reverb density out of range"};
+ props.Density = val;
break;
case AL_REVERB_DIFFUSION:
if(!(val >= AL_REVERB_MIN_DIFFUSION && val <= AL_REVERB_MAX_DIFFUSION))
- throw effect_exception{AL_INVALID_VALUE, "Reverb diffusion out of range"};
- props->Reverb.Diffusion = val;
+ throw effect_exception{AL_INVALID_VALUE, "EAX Reverb diffusion out of range"};
+ props.Diffusion = val;
break;
case AL_REVERB_GAIN:
if(!(val >= AL_REVERB_MIN_GAIN && val <= AL_REVERB_MAX_GAIN))
- throw effect_exception{AL_INVALID_VALUE, "Reverb gain out of range"};
- props->Reverb.Gain = val;
+ throw effect_exception{AL_INVALID_VALUE, "EAX Reverb gain out of range"};
+ props.Gain = val;
break;
case AL_REVERB_GAINHF:
if(!(val >= AL_REVERB_MIN_GAINHF && val <= AL_REVERB_MAX_GAINHF))
- throw effect_exception{AL_INVALID_VALUE, "Reverb gainhf out of range"};
- props->Reverb.GainHF = val;
+ throw effect_exception{AL_INVALID_VALUE, "EAX Reverb gainhf out of range"};
+ props.GainHF = val;
break;
case AL_REVERB_DECAY_TIME:
if(!(val >= AL_REVERB_MIN_DECAY_TIME && val <= AL_REVERB_MAX_DECAY_TIME))
- throw effect_exception{AL_INVALID_VALUE, "Reverb decay time out of range"};
- props->Reverb.DecayTime = val;
+ throw effect_exception{AL_INVALID_VALUE, "EAX Reverb decay time out of range"};
+ props.DecayTime = val;
break;
case AL_REVERB_DECAY_HFRATIO:
if(!(val >= AL_REVERB_MIN_DECAY_HFRATIO && val <= AL_REVERB_MAX_DECAY_HFRATIO))
- throw effect_exception{AL_INVALID_VALUE, "Reverb decay hfratio out of range"};
- props->Reverb.DecayHFRatio = val;
+ throw effect_exception{AL_INVALID_VALUE, "EAX Reverb decay hfratio out of range"};
+ props.DecayHFRatio = val;
break;
case AL_REVERB_REFLECTIONS_GAIN:
if(!(val >= AL_REVERB_MIN_REFLECTIONS_GAIN && val <= AL_REVERB_MAX_REFLECTIONS_GAIN))
- throw effect_exception{AL_INVALID_VALUE, "Reverb reflections gain out of range"};
- props->Reverb.ReflectionsGain = val;
+ throw effect_exception{AL_INVALID_VALUE, "EAX Reverb reflections gain out of range"};
+ props.ReflectionsGain = val;
break;
case AL_REVERB_REFLECTIONS_DELAY:
if(!(val >= AL_REVERB_MIN_REFLECTIONS_DELAY && val <= AL_REVERB_MAX_REFLECTIONS_DELAY))
- throw effect_exception{AL_INVALID_VALUE, "Reverb reflections delay out of range"};
- props->Reverb.ReflectionsDelay = val;
+ throw effect_exception{AL_INVALID_VALUE, "EAX Reverb reflections delay out of range"};
+ props.ReflectionsDelay = val;
break;
case AL_REVERB_LATE_REVERB_GAIN:
if(!(val >= AL_REVERB_MIN_LATE_REVERB_GAIN && val <= AL_REVERB_MAX_LATE_REVERB_GAIN))
- throw effect_exception{AL_INVALID_VALUE, "Reverb late reverb gain out of range"};
- props->Reverb.LateReverbGain = val;
+ throw effect_exception{AL_INVALID_VALUE, "EAX Reverb late reverb gain out of range"};
+ props.LateReverbGain = val;
break;
case AL_REVERB_LATE_REVERB_DELAY:
if(!(val >= AL_REVERB_MIN_LATE_REVERB_DELAY && val <= AL_REVERB_MAX_LATE_REVERB_DELAY))
- throw effect_exception{AL_INVALID_VALUE, "Reverb late reverb delay out of range"};
- props->Reverb.LateReverbDelay = val;
+ throw effect_exception{AL_INVALID_VALUE, "EAX Reverb late reverb delay out of range"};
+ props.LateReverbDelay = val;
break;
case AL_REVERB_AIR_ABSORPTION_GAINHF:
if(!(val >= AL_REVERB_MIN_AIR_ABSORPTION_GAINHF && val <= AL_REVERB_MAX_AIR_ABSORPTION_GAINHF))
- throw effect_exception{AL_INVALID_VALUE, "Reverb air absorption gainhf out of range"};
- props->Reverb.AirAbsorptionGainHF = val;
+ throw effect_exception{AL_INVALID_VALUE, "EAX Reverb air absorption gainhf out of range"};
+ props.AirAbsorptionGainHF = val;
break;
case AL_REVERB_ROOM_ROLLOFF_FACTOR:
if(!(val >= AL_REVERB_MIN_ROOM_ROLLOFF_FACTOR && val <= AL_REVERB_MAX_ROOM_ROLLOFF_FACTOR))
- throw effect_exception{AL_INVALID_VALUE, "Reverb room rolloff factor out of range"};
- props->Reverb.RoomRolloffFactor = val;
+ throw effect_exception{AL_INVALID_VALUE, "EAX Reverb room rolloff factor out of range"};
+ props.RoomRolloffFactor = val;
break;
default:
- throw effect_exception{AL_INVALID_ENUM, "Invalid reverb float property 0x%04x", param};
+ throw effect_exception{AL_INVALID_ENUM, "Invalid EAX reverb float property 0x%04x", param};
+ }
+}
+void EffectHandler::StdReverbSetParamfv(ReverbProps &props, ALenum param, const float *vals)
+{
+ switch(param)
+ {
+ default:
+ StdReverbSetParamf(props, param, vals[0]);
+ break;
}
}
-void StdReverb_setParamfv(EffectProps *props, ALenum param, const float *vals)
-{ StdReverb_setParamf(props, param, vals[0]); }
-void StdReverb_getParami(const EffectProps *props, ALenum param, int *val)
+void EffectHandler::StdReverbGetParami(const ReverbProps &props, ALenum param, int *val)
{
switch(param)
{
case AL_REVERB_DECAY_HFLIMIT:
- *val = props->Reverb.DecayHFLimit;
+ *val = props.DecayHFLimit;
break;
default:
- throw effect_exception{AL_INVALID_ENUM, "Invalid reverb integer property 0x%04x", param};
+ throw effect_exception{AL_INVALID_ENUM, "Invalid EAX reverb integer property 0x%04x",
+ param};
}
}
-void StdReverb_getParamiv(const EffectProps *props, ALenum param, int *vals)
-{ StdReverb_getParami(props, param, vals); }
-void StdReverb_getParamf(const EffectProps *props, ALenum param, float *val)
+void EffectHandler::StdReverbGetParamiv(const ReverbProps &props, ALenum param, int *vals)
+{ StdReverbGetParami(props, param, vals); }
+void EffectHandler::StdReverbGetParamf(const ReverbProps &props, ALenum param, float *val)
{
switch(param)
{
- case AL_REVERB_DENSITY:
- *val = props->Reverb.Density;
- break;
-
- case AL_REVERB_DIFFUSION:
- *val = props->Reverb.Diffusion;
- break;
-
- case AL_REVERB_GAIN:
- *val = props->Reverb.Gain;
- break;
-
- case AL_REVERB_GAINHF:
- *val = props->Reverb.GainHF;
- break;
-
- case AL_REVERB_DECAY_TIME:
- *val = props->Reverb.DecayTime;
- break;
-
- case AL_REVERB_DECAY_HFRATIO:
- *val = props->Reverb.DecayHFRatio;
- break;
-
- case AL_REVERB_REFLECTIONS_GAIN:
- *val = props->Reverb.ReflectionsGain;
- break;
-
- case AL_REVERB_REFLECTIONS_DELAY:
- *val = props->Reverb.ReflectionsDelay;
- break;
-
- case AL_REVERB_LATE_REVERB_GAIN:
- *val = props->Reverb.LateReverbGain;
- break;
-
- case AL_REVERB_LATE_REVERB_DELAY:
- *val = props->Reverb.LateReverbDelay;
- break;
-
- case AL_REVERB_AIR_ABSORPTION_GAINHF:
- *val = props->Reverb.AirAbsorptionGainHF;
- break;
-
- case AL_REVERB_ROOM_ROLLOFF_FACTOR:
- *val = props->Reverb.RoomRolloffFactor;
- break;
+ case AL_REVERB_DENSITY: *val = props.Density; break;
+ case AL_REVERB_DIFFUSION: *val = props.Diffusion; break;
+ case AL_REVERB_GAIN: *val = props.Gain; break;
+ case AL_REVERB_GAINHF: *val = props.GainHF; break;
+ case AL_REVERB_DECAY_TIME: *val = props.DecayTime; break;
+ case AL_REVERB_DECAY_HFRATIO: *val = props.DecayHFRatio; break;
+ case AL_REVERB_REFLECTIONS_GAIN: *val = props.ReflectionsGain; break;
+ case AL_REVERB_REFLECTIONS_DELAY: *val = props.ReflectionsDelay; break;
+ case AL_REVERB_LATE_REVERB_GAIN: *val = props.LateReverbGain; break;
+ case AL_REVERB_LATE_REVERB_DELAY: *val = props.LateReverbDelay; break;
+ case AL_REVERB_AIR_ABSORPTION_GAINHF: *val = props.AirAbsorptionGainHF; break;
+ case AL_REVERB_ROOM_ROLLOFF_FACTOR: *val = props.RoomRolloffFactor; break;
default:
- throw effect_exception{AL_INVALID_ENUM, "Invalid reverb float property 0x%04x", param};
+ throw effect_exception{AL_INVALID_ENUM, "Invalid EAX reverb float property 0x%04x", param};
}
}
-void StdReverb_getParamfv(const EffectProps *props, ALenum param, float *vals)
-{ StdReverb_getParamf(props, param, vals); }
-
-EffectProps genDefaultStdProps() noexcept
+void EffectHandler::StdReverbGetParamfv(const ReverbProps &props, ALenum param, float *vals)
{
- EffectProps props{};
- props.Reverb.Density = AL_REVERB_DEFAULT_DENSITY;
- props.Reverb.Diffusion = AL_REVERB_DEFAULT_DIFFUSION;
- props.Reverb.Gain = AL_REVERB_DEFAULT_GAIN;
- props.Reverb.GainHF = AL_REVERB_DEFAULT_GAINHF;
- props.Reverb.GainLF = 1.0f;
- props.Reverb.DecayTime = AL_REVERB_DEFAULT_DECAY_TIME;
- props.Reverb.DecayHFRatio = AL_REVERB_DEFAULT_DECAY_HFRATIO;
- props.Reverb.DecayLFRatio = 1.0f;
- props.Reverb.ReflectionsGain = AL_REVERB_DEFAULT_REFLECTIONS_GAIN;
- props.Reverb.ReflectionsDelay = AL_REVERB_DEFAULT_REFLECTIONS_DELAY;
- props.Reverb.ReflectionsPan[0] = 0.0f;
- props.Reverb.ReflectionsPan[1] = 0.0f;
- props.Reverb.ReflectionsPan[2] = 0.0f;
- props.Reverb.LateReverbGain = AL_REVERB_DEFAULT_LATE_REVERB_GAIN;
- props.Reverb.LateReverbDelay = AL_REVERB_DEFAULT_LATE_REVERB_DELAY;
- props.Reverb.LateReverbPan[0] = 0.0f;
- props.Reverb.LateReverbPan[1] = 0.0f;
- props.Reverb.LateReverbPan[2] = 0.0f;
- props.Reverb.EchoTime = 0.25f;
- props.Reverb.EchoDepth = 0.0f;
- props.Reverb.ModulationTime = 0.25f;
- props.Reverb.ModulationDepth = 0.0f;
- props.Reverb.AirAbsorptionGainHF = AL_REVERB_DEFAULT_AIR_ABSORPTION_GAINHF;
- props.Reverb.HFReference = 5000.0f;
- props.Reverb.LFReference = 250.0f;
- props.Reverb.RoomRolloffFactor = AL_REVERB_DEFAULT_ROOM_ROLLOFF_FACTOR;
- props.Reverb.DecayHFLimit = AL_REVERB_DEFAULT_DECAY_HFLIMIT;
- return props;
+ switch(param)
+ {
+ default:
+ StdReverbGetParamf(props, param, vals);
+ break;
+ }
}
-} // namespace
-
-DEFINE_ALEFFECT_VTABLE(Reverb);
-
-const EffectProps ReverbEffectProps{genDefaultProps()};
-
-DEFINE_ALEFFECT_VTABLE(StdReverb);
-
-const EffectProps StdReverbEffectProps{genDefaultStdProps()};
#ifdef ALSOFT_EAX
namespace {
@@ -1086,98 +1001,87 @@ struct EaxReverbCommitter::Exception : public EaxReverbEffectException
throw Exception{message};
}
-void EaxReverbCommitter::translate(const EAX_REVERBPROPERTIES& src, EaxEffectProps& dst) noexcept
+void EaxReverbCommitter::translate(const EAX_REVERBPROPERTIES& src, EAXREVERBPROPERTIES& dst) noexcept
{
assert(src.environment <= EAX1REVERB_MAXENVIRONMENT);
- auto&& eaxprops = dst.emplace<EAXREVERBPROPERTIES>(EAXREVERB_PRESETS[src.environment]);
- eaxprops.flDecayTime = src.fDecayTime_sec;
- eaxprops.flDecayHFRatio = src.fDamping;
- eaxprops.lReverb = mini(static_cast<int>(gain_to_level_mb(src.fVolume)), 0);
+ dst = EAXREVERB_PRESETS[src.environment];
+ dst.flDecayTime = src.fDecayTime_sec;
+ dst.flDecayHFRatio = src.fDamping;
+ dst.lReverb = mini(static_cast<int>(gain_to_level_mb(src.fVolume)), 0);
}
-void EaxReverbCommitter::translate(const EAX20LISTENERPROPERTIES& src, EaxEffectProps& dst) noexcept
+void EaxReverbCommitter::translate(const EAX20LISTENERPROPERTIES& src, EAXREVERBPROPERTIES& dst) noexcept
{
assert(src.dwEnvironment <= EAX1REVERB_MAXENVIRONMENT);
- auto&& eaxprops = dst.emplace<EAXREVERBPROPERTIES>(EAXREVERB_PRESETS[src.dwEnvironment]);
- eaxprops.ulEnvironment = src.dwEnvironment;
- eaxprops.flEnvironmentSize = src.flEnvironmentSize;
- eaxprops.flEnvironmentDiffusion = src.flEnvironmentDiffusion;
- eaxprops.lRoom = src.lRoom;
- eaxprops.lRoomHF = src.lRoomHF;
- eaxprops.flDecayTime = src.flDecayTime;
- eaxprops.flDecayHFRatio = src.flDecayHFRatio;
- eaxprops.lReflections = src.lReflections;
- eaxprops.flReflectionsDelay = src.flReflectionsDelay;
- eaxprops.lReverb = src.lReverb;
- eaxprops.flReverbDelay = src.flReverbDelay;
- eaxprops.flAirAbsorptionHF = src.flAirAbsorptionHF;
- eaxprops.flRoomRolloffFactor = src.flRoomRolloffFactor;
- eaxprops.ulFlags = src.dwFlags;
-}
-
-void EaxReverbCommitter::translate(const EAXREVERBPROPERTIES& src, EaxEffectProps& dst) noexcept
-{
- dst = src;
+ dst = EAXREVERB_PRESETS[src.dwEnvironment];
+ dst.ulEnvironment = src.dwEnvironment;
+ dst.flEnvironmentSize = src.flEnvironmentSize;
+ dst.flEnvironmentDiffusion = src.flEnvironmentDiffusion;
+ dst.lRoom = src.lRoom;
+ dst.lRoomHF = src.lRoomHF;
+ dst.flDecayTime = src.flDecayTime;
+ dst.flDecayHFRatio = src.flDecayHFRatio;
+ dst.lReflections = src.lReflections;
+ dst.flReflectionsDelay = src.flReflectionsDelay;
+ dst.lReverb = src.lReverb;
+ dst.flReverbDelay = src.flReverbDelay;
+ dst.flAirAbsorptionHF = src.flAirAbsorptionHF;
+ dst.flRoomRolloffFactor = src.flRoomRolloffFactor;
+ dst.ulFlags = src.dwFlags;
}
bool EaxReverbCommitter::commit(const EAX_REVERBPROPERTIES &props)
{
- EaxEffectProps dst{};
+ EAXREVERBPROPERTIES dst{};
translate(props, dst);
return commit(dst);
}
bool EaxReverbCommitter::commit(const EAX20LISTENERPROPERTIES &props)
{
- EaxEffectProps dst{};
+ EAXREVERBPROPERTIES dst{};
translate(props, dst);
return commit(dst);
}
bool EaxReverbCommitter::commit(const EAXREVERBPROPERTIES &props)
{
- EaxEffectProps dst{};
- translate(props, dst);
- return commit(dst);
-}
-
-bool EaxReverbCommitter::commit(const EaxEffectProps &props)
-{
- if(props == mEaxProps)
+ if(auto *cur = std::get_if<EAXREVERBPROPERTIES>(&mEaxProps); cur && *cur == props)
return false;
mEaxProps = props;
- auto &eaxprops = std::get<EAXREVERBPROPERTIES>(props);
- const auto size = eaxprops.flEnvironmentSize;
- const auto density = (size * size * size) / 16.0F;
- mAlProps.Reverb.Density = std::min(density, AL_EAXREVERB_MAX_DENSITY);
- mAlProps.Reverb.Diffusion = eaxprops.flEnvironmentDiffusion;
- mAlProps.Reverb.Gain = level_mb_to_gain(static_cast<float>(eaxprops.lRoom));
- mAlProps.Reverb.GainHF = level_mb_to_gain(static_cast<float>(eaxprops.lRoomHF));
- mAlProps.Reverb.GainLF = level_mb_to_gain(static_cast<float>(eaxprops.lRoomLF));
- mAlProps.Reverb.DecayTime = eaxprops.flDecayTime;
- mAlProps.Reverb.DecayHFRatio = eaxprops.flDecayHFRatio;
- mAlProps.Reverb.DecayLFRatio = eaxprops.flDecayLFRatio;
- mAlProps.Reverb.ReflectionsGain = level_mb_to_gain(static_cast<float>(eaxprops.lReflections));
- mAlProps.Reverb.ReflectionsDelay = eaxprops.flReflectionsDelay;
- mAlProps.Reverb.ReflectionsPan[0] = eaxprops.vReflectionsPan.x;
- mAlProps.Reverb.ReflectionsPan[1] = eaxprops.vReflectionsPan.y;
- mAlProps.Reverb.ReflectionsPan[2] = eaxprops.vReflectionsPan.z;
- mAlProps.Reverb.LateReverbGain = level_mb_to_gain(static_cast<float>(eaxprops.lReverb));
- mAlProps.Reverb.LateReverbDelay = eaxprops.flReverbDelay;
- mAlProps.Reverb.LateReverbPan[0] = eaxprops.vReverbPan.x;
- mAlProps.Reverb.LateReverbPan[1] = eaxprops.vReverbPan.y;
- mAlProps.Reverb.LateReverbPan[2] = eaxprops.vReverbPan.z;
- mAlProps.Reverb.EchoTime = eaxprops.flEchoTime;
- mAlProps.Reverb.EchoDepth = eaxprops.flEchoDepth;
- mAlProps.Reverb.ModulationTime = eaxprops.flModulationTime;
- mAlProps.Reverb.ModulationDepth = eaxprops.flModulationDepth;
- mAlProps.Reverb.AirAbsorptionGainHF = level_mb_to_gain(eaxprops.flAirAbsorptionHF);
- mAlProps.Reverb.HFReference = eaxprops.flHFReference;
- mAlProps.Reverb.LFReference = eaxprops.flLFReference;
- mAlProps.Reverb.RoomRolloffFactor = eaxprops.flRoomRolloffFactor;
- mAlProps.Reverb.DecayHFLimit = ((eaxprops.ulFlags & EAXREVERBFLAGS_DECAYHFLIMIT) != 0);
+ const auto size = props.flEnvironmentSize;
+ const auto density = (size * size * size) / 16.0f;
+ mAlProps = [&]{
+ ReverbProps ret{};
+ ret.Density = std::min(density, AL_EAXREVERB_MAX_DENSITY);
+ ret.Diffusion = props.flEnvironmentDiffusion;
+ ret.Gain = level_mb_to_gain(static_cast<float>(props.lRoom));
+ ret.GainHF = level_mb_to_gain(static_cast<float>(props.lRoomHF));
+ ret.GainLF = level_mb_to_gain(static_cast<float>(props.lRoomLF));
+ ret.DecayTime = props.flDecayTime;
+ ret.DecayHFRatio = props.flDecayHFRatio;
+ ret.DecayLFRatio = props.flDecayLFRatio;
+ ret.ReflectionsGain = level_mb_to_gain(static_cast<float>(props.lReflections));
+ ret.ReflectionsDelay = props.flReflectionsDelay;
+ ret.ReflectionsPan = {props.vReflectionsPan.x, props.vReflectionsPan.y,
+ props.vReflectionsPan.z};
+ ret.LateReverbGain = level_mb_to_gain(static_cast<float>(props.lReverb));
+ ret.LateReverbDelay = props.flReverbDelay;
+ ret.LateReverbPan = {props.vReverbPan.x, props.vReverbPan.y, props.vReverbPan.z};
+ ret.EchoTime = props.flEchoTime;
+ ret.EchoDepth = props.flEchoDepth;
+ ret.ModulationTime = props.flModulationTime;
+ ret.ModulationDepth = props.flModulationDepth;
+ ret.AirAbsorptionGainHF = level_mb_to_gain(props.flAirAbsorptionHF);
+ ret.HFReference = props.flHFReference;
+ ret.LFReference = props.flLFReference;
+ ret.RoomRolloffFactor = props.flRoomRolloffFactor;
+ ret.DecayHFLimit = ((props.ulFlags & EAXREVERBFLAGS_DECAYHFLIMIT) != 0);
+ return ret;
+ }();
+
return true;
}
@@ -1274,11 +1178,6 @@ void EaxReverbCommitter::Get(const EaxCall &call, const EAXREVERBPROPERTIES &pro
}
}
-void EaxReverbCommitter::Get(const EaxCall &call, const EaxEffectProps &props)
-{
- Get(call, std::get<EAXREVERBPROPERTIES>(props));
-}
-
void EaxReverbCommitter::Set(const EaxCall &call, EAX_REVERBPROPERTIES &props)
{
@@ -1297,71 +1196,23 @@ void EaxReverbCommitter::Set(const EaxCall &call, EAX20LISTENERPROPERTIES &props
{
switch(call.get_property_id())
{
- case DSPROPERTY_EAX20LISTENER_NONE:
- break;
-
- case DSPROPERTY_EAX20LISTENER_ALLPARAMETERS:
- defer<AllValidator2>(call, props);
- break;
-
- case DSPROPERTY_EAX20LISTENER_ROOM:
- defer<RoomValidator>(call, props.lRoom);
- break;
-
- case DSPROPERTY_EAX20LISTENER_ROOMHF:
- defer<RoomHFValidator>(call, props.lRoomHF);
- break;
-
- case DSPROPERTY_EAX20LISTENER_ROOMROLLOFFFACTOR:
- defer<RoomRolloffFactorValidator>(call, props.flRoomRolloffFactor);
- break;
-
- case DSPROPERTY_EAX20LISTENER_DECAYTIME:
- defer<DecayTimeValidator>(call, props.flDecayTime);
- break;
-
- case DSPROPERTY_EAX20LISTENER_DECAYHFRATIO:
- defer<DecayHFRatioValidator>(call, props.flDecayHFRatio);
- break;
-
- case DSPROPERTY_EAX20LISTENER_REFLECTIONS:
- defer<ReflectionsValidator>(call, props.lReflections);
- break;
-
- case DSPROPERTY_EAX20LISTENER_REFLECTIONSDELAY:
- defer<ReflectionsDelayValidator>(call, props.flReverbDelay);
- break;
-
- case DSPROPERTY_EAX20LISTENER_REVERB:
- defer<ReverbValidator>(call, props.lReverb);
- break;
-
- case DSPROPERTY_EAX20LISTENER_REVERBDELAY:
- defer<ReverbDelayValidator>(call, props.flReverbDelay);
- break;
-
- case DSPROPERTY_EAX20LISTENER_ENVIRONMENT:
- defer<EnvironmentValidator1, EnvironmentDeferrer2>(call, props, props.dwEnvironment);
- break;
-
- case DSPROPERTY_EAX20LISTENER_ENVIRONMENTSIZE:
- defer<EnvironmentSizeValidator, EnvironmentSizeDeferrer2>(call, props, props.flEnvironmentSize);
- break;
-
- case DSPROPERTY_EAX20LISTENER_ENVIRONMENTDIFFUSION:
- defer<EnvironmentDiffusionValidator>(call, props.flEnvironmentDiffusion);
- break;
-
- case DSPROPERTY_EAX20LISTENER_AIRABSORPTIONHF:
- defer<AirAbsorptionHFValidator>(call, props.flAirAbsorptionHF);
- break;
-
- case DSPROPERTY_EAX20LISTENER_FLAGS:
- defer<FlagsValidator2>(call, props.dwFlags);
- break;
-
- default:
- fail_unknown_property_id();
+ case DSPROPERTY_EAX20LISTENER_NONE: break;
+ case DSPROPERTY_EAX20LISTENER_ALLPARAMETERS: defer<AllValidator2>(call, props); break;
+ case DSPROPERTY_EAX20LISTENER_ROOM: defer<RoomValidator>(call, props.lRoom); break;
+ case DSPROPERTY_EAX20LISTENER_ROOMHF: defer<RoomHFValidator>(call, props.lRoomHF); break;
+ case DSPROPERTY_EAX20LISTENER_ROOMROLLOFFFACTOR: defer<RoomRolloffFactorValidator>(call, props.flRoomRolloffFactor); break;
+ case DSPROPERTY_EAX20LISTENER_DECAYTIME: defer<DecayTimeValidator>(call, props.flDecayTime); break;
+ case DSPROPERTY_EAX20LISTENER_DECAYHFRATIO: defer<DecayHFRatioValidator>(call, props.flDecayHFRatio); break;
+ case DSPROPERTY_EAX20LISTENER_REFLECTIONS: defer<ReflectionsValidator>(call, props.lReflections); break;
+ case DSPROPERTY_EAX20LISTENER_REFLECTIONSDELAY: defer<ReflectionsDelayValidator>(call, props.flReverbDelay); break;
+ case DSPROPERTY_EAX20LISTENER_REVERB: defer<ReverbValidator>(call, props.lReverb); break;
+ case DSPROPERTY_EAX20LISTENER_REVERBDELAY: defer<ReverbDelayValidator>(call, props.flReverbDelay); break;
+ case DSPROPERTY_EAX20LISTENER_ENVIRONMENT: defer<EnvironmentValidator1, EnvironmentDeferrer2>(call, props, props.dwEnvironment); break;
+ case DSPROPERTY_EAX20LISTENER_ENVIRONMENTSIZE: defer<EnvironmentSizeValidator, EnvironmentSizeDeferrer2>(call, props, props.flEnvironmentSize); break;
+ case DSPROPERTY_EAX20LISTENER_ENVIRONMENTDIFFUSION: defer<EnvironmentDiffusionValidator>(call, props.flEnvironmentDiffusion); break;
+ case DSPROPERTY_EAX20LISTENER_AIRABSORPTIONHF: defer<AirAbsorptionHFValidator>(call, props.flAirAbsorptionHF); break;
+ case DSPROPERTY_EAX20LISTENER_FLAGS: defer<FlagsValidator2>(call, props.dwFlags); break;
+ default: fail_unknown_property_id();
}
}
@@ -1369,117 +1220,34 @@ void EaxReverbCommitter::Set(const EaxCall &call, EAXREVERBPROPERTIES &props)
{
switch(call.get_property_id())
{
- case EAXREVERB_NONE:
- break;
-
- case EAXREVERB_ALLPARAMETERS:
- defer<AllValidator3>(call, props);
- break;
-
- case EAXREVERB_ENVIRONMENT:
- defer<EnvironmentValidator3, EnvironmentDeferrer3>(call, props, props.ulEnvironment);
- break;
-
- case EAXREVERB_ENVIRONMENTSIZE:
- defer<EnvironmentSizeValidator, EnvironmentSizeDeferrer3>(call, props, props.flEnvironmentSize);
- break;
-
- case EAXREVERB_ENVIRONMENTDIFFUSION:
- defer3<EnvironmentDiffusionValidator>(call, props, props.flEnvironmentDiffusion);
- break;
-
- case EAXREVERB_ROOM:
- defer3<RoomValidator>(call, props, props.lRoom);
- break;
-
- case EAXREVERB_ROOMHF:
- defer3<RoomHFValidator>(call, props, props.lRoomHF);
- break;
-
- case EAXREVERB_ROOMLF:
- defer3<RoomLFValidator>(call, props, props.lRoomLF);
- break;
-
- case EAXREVERB_DECAYTIME:
- defer3<DecayTimeValidator>(call, props, props.flDecayTime);
- break;
-
- case EAXREVERB_DECAYHFRATIO:
- defer3<DecayHFRatioValidator>(call, props, props.flDecayHFRatio);
- break;
-
- case EAXREVERB_DECAYLFRATIO:
- defer3<DecayLFRatioValidator>(call, props, props.flDecayLFRatio);
- break;
-
- case EAXREVERB_REFLECTIONS:
- defer3<ReflectionsValidator>(call, props, props.lReflections);
- break;
-
- case EAXREVERB_REFLECTIONSDELAY:
- defer3<ReflectionsDelayValidator>(call, props, props.flReflectionsDelay);
- break;
-
- case EAXREVERB_REFLECTIONSPAN:
- defer3<VectorValidator>(call, props, props.vReflectionsPan);
- break;
-
- case EAXREVERB_REVERB:
- defer3<ReverbValidator>(call, props, props.lReverb);
- break;
-
- case EAXREVERB_REVERBDELAY:
- defer3<ReverbDelayValidator>(call, props, props.flReverbDelay);
- break;
-
- case EAXREVERB_REVERBPAN:
- defer3<VectorValidator>(call, props, props.vReverbPan);
- break;
-
- case EAXREVERB_ECHOTIME:
- defer3<EchoTimeValidator>(call, props, props.flEchoTime);
- break;
-
- case EAXREVERB_ECHODEPTH:
- defer3<EchoDepthValidator>(call, props, props.flEchoDepth);
- break;
-
- case EAXREVERB_MODULATIONTIME:
- defer3<ModulationTimeValidator>(call, props, props.flModulationTime);
- break;
-
- case EAXREVERB_MODULATIONDEPTH:
- defer3<ModulationDepthValidator>(call, props, props.flModulationDepth);
- break;
-
- case EAXREVERB_AIRABSORPTIONHF:
- defer3<AirAbsorptionHFValidator>(call, props, props.flAirAbsorptionHF);
- break;
-
- case EAXREVERB_HFREFERENCE:
- defer3<HFReferenceValidator>(call, props, props.flHFReference);
- break;
-
- case EAXREVERB_LFREFERENCE:
- defer3<LFReferenceValidator>(call, props, props.flLFReference);
- break;
-
- case EAXREVERB_ROOMROLLOFFFACTOR:
- defer3<RoomRolloffFactorValidator>(call, props, props.flRoomRolloffFactor);
- break;
-
- case EAXREVERB_FLAGS:
- defer3<FlagsValidator3>(call, props, props.ulFlags);
- break;
-
- default:
- fail_unknown_property_id();
+ case EAXREVERB_NONE: break;
+ case EAXREVERB_ALLPARAMETERS: defer<AllValidator3>(call, props); break;
+ case EAXREVERB_ENVIRONMENT: defer<EnvironmentValidator3, EnvironmentDeferrer3>(call, props, props.ulEnvironment); break;
+ case EAXREVERB_ENVIRONMENTSIZE: defer<EnvironmentSizeValidator, EnvironmentSizeDeferrer3>(call, props, props.flEnvironmentSize); break;
+ case EAXREVERB_ENVIRONMENTDIFFUSION: defer3<EnvironmentDiffusionValidator>(call, props, props.flEnvironmentDiffusion); break;
+ case EAXREVERB_ROOM: defer3<RoomValidator>(call, props, props.lRoom); break;
+ case EAXREVERB_ROOMHF: defer3<RoomHFValidator>(call, props, props.lRoomHF); break;
+ case EAXREVERB_ROOMLF: defer3<RoomLFValidator>(call, props, props.lRoomLF); break;
+ case EAXREVERB_DECAYTIME: defer3<DecayTimeValidator>(call, props, props.flDecayTime); break;
+ case EAXREVERB_DECAYHFRATIO: defer3<DecayHFRatioValidator>(call, props, props.flDecayHFRatio); break;
+ case EAXREVERB_DECAYLFRATIO: defer3<DecayLFRatioValidator>(call, props, props.flDecayLFRatio); break;
+ case EAXREVERB_REFLECTIONS: defer3<ReflectionsValidator>(call, props, props.lReflections); break;
+ case EAXREVERB_REFLECTIONSDELAY: defer3<ReflectionsDelayValidator>(call, props, props.flReflectionsDelay); break;
+ case EAXREVERB_REFLECTIONSPAN: defer3<VectorValidator>(call, props, props.vReflectionsPan); break;
+ case EAXREVERB_REVERB: defer3<ReverbValidator>(call, props, props.lReverb); break;
+ case EAXREVERB_REVERBDELAY: defer3<ReverbDelayValidator>(call, props, props.flReverbDelay); break;
+ case EAXREVERB_REVERBPAN: defer3<VectorValidator>(call, props, props.vReverbPan); break;
+ case EAXREVERB_ECHOTIME: defer3<EchoTimeValidator>(call, props, props.flEchoTime); break;
+ case EAXREVERB_ECHODEPTH: defer3<EchoDepthValidator>(call, props, props.flEchoDepth); break;
+ case EAXREVERB_MODULATIONTIME: defer3<ModulationTimeValidator>(call, props, props.flModulationTime); break;
+ case EAXREVERB_MODULATIONDEPTH: defer3<ModulationDepthValidator>(call, props, props.flModulationDepth); break;
+ case EAXREVERB_AIRABSORPTIONHF: defer3<AirAbsorptionHFValidator>(call, props, props.flAirAbsorptionHF); break;
+ case EAXREVERB_HFREFERENCE: defer3<HFReferenceValidator>(call, props, props.flHFReference); break;
+ case EAXREVERB_LFREFERENCE: defer3<LFReferenceValidator>(call, props, props.flLFReference); break;
+ case EAXREVERB_ROOMROLLOFFFACTOR: defer3<RoomRolloffFactorValidator>(call, props, props.flRoomRolloffFactor); break;
+ case EAXREVERB_FLAGS: defer3<FlagsValidator3>(call, props, props.ulFlags); break;
+ default: fail_unknown_property_id();
}
}
-void EaxReverbCommitter::Set(const EaxCall &call, EaxEffectProps &props)
-{
- Set(call, std::get<EAXREVERBPROPERTIES>(props));
-}
-
#endif // ALSOFT_EAX
diff --git a/al/effects/vmorpher.cpp b/al/effects/vmorpher.cpp
index f2551229..35a64d32 100644
--- a/al/effects/vmorpher.cpp
+++ b/al/effects/vmorpher.cpp
@@ -122,13 +122,29 @@ ALenum EnumFromWaveform(VMorpherWaveform type)
std::to_string(static_cast<int>(type))};
}
-void Vmorpher_setParami(EffectProps *props, ALenum param, int val)
+EffectProps genDefaultProps() noexcept
+{
+ VmorpherProps props{};
+ props.Rate = AL_VOCAL_MORPHER_DEFAULT_RATE;
+ props.PhonemeA = PhenomeFromEnum(AL_VOCAL_MORPHER_DEFAULT_PHONEMEA).value();
+ props.PhonemeB = PhenomeFromEnum(AL_VOCAL_MORPHER_DEFAULT_PHONEMEB).value();
+ props.PhonemeACoarseTuning = AL_VOCAL_MORPHER_DEFAULT_PHONEMEA_COARSE_TUNING;
+ props.PhonemeBCoarseTuning = AL_VOCAL_MORPHER_DEFAULT_PHONEMEB_COARSE_TUNING;
+ props.Waveform = WaveformFromEmum(AL_VOCAL_MORPHER_DEFAULT_WAVEFORM).value();
+ return props;
+}
+
+} // namespace
+
+const EffectProps VmorpherEffectProps{genDefaultProps()};
+
+void EffectHandler::SetParami(VmorpherProps &props, ALenum param, int val)
{
switch(param)
{
case AL_VOCAL_MORPHER_PHONEMEA:
if(auto phenomeopt = PhenomeFromEnum(val))
- props->Vmorpher.PhonemeA = *phenomeopt;
+ props.PhonemeA = *phenomeopt;
else
throw effect_exception{AL_INVALID_VALUE, "Vocal morpher phoneme-a out of range: 0x%04x", val};
break;
@@ -136,12 +152,12 @@ void Vmorpher_setParami(EffectProps *props, ALenum param, int val)
case AL_VOCAL_MORPHER_PHONEMEA_COARSE_TUNING:
if(!(val >= AL_VOCAL_MORPHER_MIN_PHONEMEA_COARSE_TUNING && val <= AL_VOCAL_MORPHER_MAX_PHONEMEA_COARSE_TUNING))
throw effect_exception{AL_INVALID_VALUE, "Vocal morpher phoneme-a coarse tuning out of range"};
- props->Vmorpher.PhonemeACoarseTuning = val;
+ props.PhonemeACoarseTuning = val;
break;
case AL_VOCAL_MORPHER_PHONEMEB:
if(auto phenomeopt = PhenomeFromEnum(val))
- props->Vmorpher.PhonemeB = *phenomeopt;
+ props.PhonemeB = *phenomeopt;
else
throw effect_exception{AL_INVALID_VALUE, "Vocal morpher phoneme-b out of range: 0x%04x", val};
break;
@@ -149,12 +165,12 @@ void Vmorpher_setParami(EffectProps *props, ALenum param, int val)
case AL_VOCAL_MORPHER_PHONEMEB_COARSE_TUNING:
if(!(val >= AL_VOCAL_MORPHER_MIN_PHONEMEB_COARSE_TUNING && val <= AL_VOCAL_MORPHER_MAX_PHONEMEB_COARSE_TUNING))
throw effect_exception{AL_INVALID_VALUE, "Vocal morpher phoneme-b coarse tuning out of range"};
- props->Vmorpher.PhonemeBCoarseTuning = val;
+ props.PhonemeBCoarseTuning = val;
break;
case AL_VOCAL_MORPHER_WAVEFORM:
if(auto formopt = WaveformFromEmum(val))
- props->Vmorpher.Waveform = *formopt;
+ props.Waveform = *formopt;
else
throw effect_exception{AL_INVALID_VALUE, "Vocal morpher waveform out of range: 0x%04x", val};
break;
@@ -164,19 +180,19 @@ void Vmorpher_setParami(EffectProps *props, ALenum param, int val)
param};
}
}
-void Vmorpher_setParamiv(EffectProps*, ALenum param, const int*)
+void EffectHandler::SetParamiv(VmorpherProps&, ALenum param, const int*)
{
throw effect_exception{AL_INVALID_ENUM, "Invalid vocal morpher integer-vector property 0x%04x",
param};
}
-void Vmorpher_setParamf(EffectProps *props, ALenum param, float val)
+void EffectHandler::SetParamf(VmorpherProps &props, ALenum param, float val)
{
switch(param)
{
case AL_VOCAL_MORPHER_RATE:
if(!(val >= AL_VOCAL_MORPHER_MIN_RATE && val <= AL_VOCAL_MORPHER_MAX_RATE))
throw effect_exception{AL_INVALID_VALUE, "Vocal morpher rate out of range"};
- props->Vmorpher.Rate = val;
+ props.Rate = val;
break;
default:
@@ -184,49 +200,35 @@ void Vmorpher_setParamf(EffectProps *props, ALenum param, float val)
param};
}
}
-void Vmorpher_setParamfv(EffectProps *props, ALenum param, const float *vals)
-{ Vmorpher_setParamf(props, param, vals[0]); }
+void EffectHandler::SetParamfv(VmorpherProps &props, ALenum param, const float *vals)
+{ SetParamf(props, param, vals[0]); }
-void Vmorpher_getParami(const EffectProps *props, ALenum param, int* val)
+void EffectHandler::GetParami(const VmorpherProps &props, ALenum param, int* val)
{
switch(param)
{
- case AL_VOCAL_MORPHER_PHONEMEA:
- *val = EnumFromPhenome(props->Vmorpher.PhonemeA);
- break;
-
- case AL_VOCAL_MORPHER_PHONEMEA_COARSE_TUNING:
- *val = props->Vmorpher.PhonemeACoarseTuning;
- break;
-
- case AL_VOCAL_MORPHER_PHONEMEB:
- *val = EnumFromPhenome(props->Vmorpher.PhonemeB);
- break;
-
- case AL_VOCAL_MORPHER_PHONEMEB_COARSE_TUNING:
- *val = props->Vmorpher.PhonemeBCoarseTuning;
- break;
-
- case AL_VOCAL_MORPHER_WAVEFORM:
- *val = EnumFromWaveform(props->Vmorpher.Waveform);
- break;
+ case AL_VOCAL_MORPHER_PHONEMEA: *val = EnumFromPhenome(props.PhonemeA); break;
+ case AL_VOCAL_MORPHER_PHONEMEA_COARSE_TUNING: *val = props.PhonemeACoarseTuning; break;
+ case AL_VOCAL_MORPHER_PHONEMEB: *val = EnumFromPhenome(props.PhonemeB); break;
+ case AL_VOCAL_MORPHER_PHONEMEB_COARSE_TUNING: *val = props.PhonemeBCoarseTuning; break;
+ case AL_VOCAL_MORPHER_WAVEFORM: *val = EnumFromWaveform(props.Waveform); break;
default:
throw effect_exception{AL_INVALID_ENUM, "Invalid vocal morpher integer property 0x%04x",
param};
}
}
-void Vmorpher_getParamiv(const EffectProps*, ALenum param, int*)
+void EffectHandler::GetParamiv(const VmorpherProps&, ALenum param, int*)
{
throw effect_exception{AL_INVALID_ENUM, "Invalid vocal morpher integer-vector property 0x%04x",
param};
}
-void Vmorpher_getParamf(const EffectProps *props, ALenum param, float *val)
+void EffectHandler::GetParamf(const VmorpherProps &props, ALenum param, float *val)
{
switch(param)
{
case AL_VOCAL_MORPHER_RATE:
- *val = props->Vmorpher.Rate;
+ *val = props.Rate;
break;
default:
@@ -234,26 +236,9 @@ void Vmorpher_getParamf(const EffectProps *props, ALenum param, float *val)
param};
}
}
-void Vmorpher_getParamfv(const EffectProps *props, ALenum param, float *vals)
-{ Vmorpher_getParamf(props, param, vals); }
-
-EffectProps genDefaultProps() noexcept
-{
- EffectProps props{};
- props.Vmorpher.Rate = AL_VOCAL_MORPHER_DEFAULT_RATE;
- props.Vmorpher.PhonemeA = *PhenomeFromEnum(AL_VOCAL_MORPHER_DEFAULT_PHONEMEA);
- props.Vmorpher.PhonemeB = *PhenomeFromEnum(AL_VOCAL_MORPHER_DEFAULT_PHONEMEB);
- props.Vmorpher.PhonemeACoarseTuning = AL_VOCAL_MORPHER_DEFAULT_PHONEMEA_COARSE_TUNING;
- props.Vmorpher.PhonemeBCoarseTuning = AL_VOCAL_MORPHER_DEFAULT_PHONEMEB_COARSE_TUNING;
- props.Vmorpher.Waveform = *WaveformFromEmum(AL_VOCAL_MORPHER_DEFAULT_WAVEFORM);
- return props;
-}
-
-} // namespace
+void EffectHandler::GetParamfv(const VmorpherProps &props, ALenum param, float *vals)
+{ GetParamf(props, param, vals); }
-DEFINE_ALEFFECT_VTABLE(Vmorpher);
-
-const EffectProps VmorpherEffectProps{genDefaultProps()};
#ifdef ALSOFT_EAX
namespace {
@@ -352,10 +337,9 @@ template<>
throw Exception{message};
}
-template<>
-bool VocalMorpherCommitter::commit(const EaxEffectProps &props)
+bool EaxVocalMorpherCommitter::commit(const EAXVOCALMORPHERPROPERTIES &props)
{
- if(props == mEaxProps)
+ if(auto *cur = std::get_if<EAXVOCALMORPHERPROPERTIES>(&mEaxProps); cur && *cur == props)
return false;
mEaxProps = props;
@@ -407,19 +391,21 @@ bool VocalMorpherCommitter::commit(const EaxEffectProps &props)
return VMorpherWaveform::Sinusoid;
};
- auto &eaxprops = std::get<EAXVOCALMORPHERPROPERTIES>(props);
- mAlProps.Vmorpher.PhonemeA = get_phoneme(eaxprops.ulPhonemeA);
- mAlProps.Vmorpher.PhonemeACoarseTuning = static_cast<int>(eaxprops.lPhonemeACoarseTuning);
- mAlProps.Vmorpher.PhonemeB = get_phoneme(eaxprops.ulPhonemeB);
- mAlProps.Vmorpher.PhonemeBCoarseTuning = static_cast<int>(eaxprops.lPhonemeBCoarseTuning);
- mAlProps.Vmorpher.Waveform = get_waveform(eaxprops.ulWaveform);
- mAlProps.Vmorpher.Rate = eaxprops.flRate;
+ mAlProps = [&]{
+ VmorpherProps ret{};
+ ret.PhonemeA = get_phoneme(props.ulPhonemeA);
+ ret.PhonemeACoarseTuning = static_cast<int>(props.lPhonemeACoarseTuning);
+ ret.PhonemeB = get_phoneme(props.ulPhonemeB);
+ ret.PhonemeBCoarseTuning = static_cast<int>(props.lPhonemeBCoarseTuning);
+ ret.Waveform = get_waveform(props.ulWaveform);
+ ret.Rate = props.flRate;
+ return ret;
+ }();
return true;
}
-template<>
-void VocalMorpherCommitter::SetDefaults(EaxEffectProps &props)
+void EaxVocalMorpherCommitter::SetDefaults(EaxEffectProps &props)
{
static constexpr EAXVOCALMORPHERPROPERTIES defprops{[]
{
@@ -435,87 +421,35 @@ void VocalMorpherCommitter::SetDefaults(EaxEffectProps &props)
props = defprops;
}
-template<>
-void VocalMorpherCommitter::Get(const EaxCall &call, const EaxEffectProps &props_)
+void EaxVocalMorpherCommitter::Get(const EaxCall &call, const EAXVOCALMORPHERPROPERTIES &props)
{
- auto &props = std::get<EAXVOCALMORPHERPROPERTIES>(props_);
switch(call.get_property_id())
{
- case EAXVOCALMORPHER_NONE:
- break;
-
- case EAXVOCALMORPHER_ALLPARAMETERS:
- call.set_value<Exception>(props);
- break;
-
- case EAXVOCALMORPHER_PHONEMEA:
- call.set_value<Exception>(props.ulPhonemeA);
- break;
-
- case EAXVOCALMORPHER_PHONEMEACOARSETUNING:
- call.set_value<Exception>(props.lPhonemeACoarseTuning);
- break;
-
- case EAXVOCALMORPHER_PHONEMEB:
- call.set_value<Exception>(props.ulPhonemeB);
- break;
-
- case EAXVOCALMORPHER_PHONEMEBCOARSETUNING:
- call.set_value<Exception>(props.lPhonemeBCoarseTuning);
- break;
-
- case EAXVOCALMORPHER_WAVEFORM:
- call.set_value<Exception>(props.ulWaveform);
- break;
-
- case EAXVOCALMORPHER_RATE:
- call.set_value<Exception>(props.flRate);
- break;
-
- default:
- fail_unknown_property_id();
+ case EAXVOCALMORPHER_NONE: break;
+ case EAXVOCALMORPHER_ALLPARAMETERS: call.set_value<Exception>(props); break;
+ case EAXVOCALMORPHER_PHONEMEA: call.set_value<Exception>(props.ulPhonemeA); break;
+ case EAXVOCALMORPHER_PHONEMEACOARSETUNING: call.set_value<Exception>(props.lPhonemeACoarseTuning); break;
+ case EAXVOCALMORPHER_PHONEMEB: call.set_value<Exception>(props.ulPhonemeB); break;
+ case EAXVOCALMORPHER_PHONEMEBCOARSETUNING: call.set_value<Exception>(props.lPhonemeBCoarseTuning); break;
+ case EAXVOCALMORPHER_WAVEFORM: call.set_value<Exception>(props.ulWaveform); break;
+ case EAXVOCALMORPHER_RATE: call.set_value<Exception>(props.flRate); break;
+ default: fail_unknown_property_id();
}
}
-template<>
-void VocalMorpherCommitter::Set(const EaxCall &call, EaxEffectProps &props_)
+void EaxVocalMorpherCommitter::Set(const EaxCall &call, EAXVOCALMORPHERPROPERTIES &props)
{
- auto &props = std::get<EAXVOCALMORPHERPROPERTIES>(props_);
switch(call.get_property_id())
{
- case EAXVOCALMORPHER_NONE:
- break;
-
- case EAXVOCALMORPHER_ALLPARAMETERS:
- defer<AllValidator>(call, props);
- break;
-
- case EAXVOCALMORPHER_PHONEMEA:
- defer<PhonemeAValidator>(call, props.ulPhonemeA);
- break;
-
- case EAXVOCALMORPHER_PHONEMEACOARSETUNING:
- defer<PhonemeACoarseTuningValidator>(call, props.lPhonemeACoarseTuning);
- break;
-
- case EAXVOCALMORPHER_PHONEMEB:
- defer<PhonemeBValidator>(call, props.ulPhonemeB);
- break;
-
- case EAXVOCALMORPHER_PHONEMEBCOARSETUNING:
- defer<PhonemeBCoarseTuningValidator>(call, props.lPhonemeBCoarseTuning);
- break;
-
- case EAXVOCALMORPHER_WAVEFORM:
- defer<WaveformValidator>(call, props.ulWaveform);
- break;
-
- case EAXVOCALMORPHER_RATE:
- defer<RateValidator>(call, props.flRate);
- break;
-
- default:
- fail_unknown_property_id();
+ case EAXVOCALMORPHER_NONE: break;
+ case EAXVOCALMORPHER_ALLPARAMETERS: defer<AllValidator>(call, props); break;
+ case EAXVOCALMORPHER_PHONEMEA: defer<PhonemeAValidator>(call, props.ulPhonemeA); break;
+ case EAXVOCALMORPHER_PHONEMEACOARSETUNING: defer<PhonemeACoarseTuningValidator>(call, props.lPhonemeACoarseTuning); break;
+ case EAXVOCALMORPHER_PHONEMEB: defer<PhonemeBValidator>(call, props.ulPhonemeB); break;
+ case EAXVOCALMORPHER_PHONEMEBCOARSETUNING: defer<PhonemeBCoarseTuningValidator>(call, props.lPhonemeBCoarseTuning); break;
+ case EAXVOCALMORPHER_WAVEFORM: defer<WaveformValidator>(call, props.ulWaveform); break;
+ case EAXVOCALMORPHER_RATE: defer<RateValidator>(call, props.flRate); break;
+ default: fail_unknown_property_id();
}
}
diff --git a/al/error.cpp b/al/error.cpp
index c2359477..26dc522f 100644
--- a/al/error.cpp
+++ b/al/error.cpp
@@ -99,41 +99,39 @@ void ALCcontext::setError(ALenum errorCode, const char *msg, ...)
/* Special-case alGetError since it (potentially) raises a debug signal and
* returns a non-default value for a null context.
*/
-AL_API ALenum AL_APIENTRY alGetError(void) noexcept
+AL_API auto AL_APIENTRY alGetError() noexcept -> ALenum
{
- auto context = GetContextRef();
- if(!context) UNLIKELY
+ if(auto context = GetContextRef()) LIKELY
+ return alGetErrorDirect(context.get());
+
+ static const ALenum deferror{[](const char *envname, const char *optname) -> ALenum
{
- static const ALenum deferror{[](const char *envname, const char *optname) -> ALenum
- {
- auto optstr = al::getenv(envname);
- if(!optstr)
- optstr = ConfigValueStr(nullptr, "game_compat", optname);
-
- if(optstr)
- {
- char *end{};
- auto value = std::strtoul(optstr->c_str(), &end, 0);
- if(end && *end == '\0' && value <= std::numeric_limits<ALenum>::max())
- return static_cast<ALenum>(value);
- ERR("Invalid default error value: \"%s\"", optstr->c_str());
- }
- return AL_INVALID_OPERATION;
- }("__ALSOFT_DEFAULT_ERROR", "default-error")};
-
- WARN("Querying error state on null context (implicitly 0x%04x)\n", deferror);
- if(TrapALError)
+ auto optstr = al::getenv(envname);
+ if(!optstr)
+ optstr = ConfigValueStr({}, "game_compat", optname);
+
+ if(optstr)
{
+ char *end{};
+ auto value = std::strtoul(optstr->c_str(), &end, 0);
+ if(end && *end == '\0' && value <= std::numeric_limits<ALenum>::max())
+ return static_cast<ALenum>(value);
+ ERR("Invalid default error value: \"%s\"", optstr->c_str());
+ }
+ return AL_INVALID_OPERATION;
+ }("__ALSOFT_DEFAULT_ERROR", "default-error")};
+
+ WARN("Querying error state on null context (implicitly 0x%04x)\n", deferror);
+ if(TrapALError)
+ {
#ifdef _WIN32
- if(IsDebuggerPresent())
- DebugBreak();
+ if(IsDebuggerPresent())
+ DebugBreak();
#elif defined(SIGTRAP)
- raise(SIGTRAP);
+ raise(SIGTRAP);
#endif
- }
- return deferror;
}
- return alGetErrorDirect(context.get());
+ return deferror;
}
FORCE_ALIGN ALenum AL_APIENTRY alGetErrorDirect(ALCcontext *context) noexcept
diff --git a/al/event.cpp b/al/event.cpp
index 8b76ceff..95b07dc2 100644
--- a/al/event.cpp
+++ b/al/event.cpp
@@ -118,7 +118,7 @@ int EventThread(ALCcontext *context)
};
auto proc_disconnect = [context,enabledevts](AsyncDisconnectEvent &evt)
{
- const std::string_view message{evt.msg};
+ const std::string_view message{evt.msg.data()};
context->debugMessage(DebugSource::System, DebugType::Error, 0,
DebugSeverity::High, message);
diff --git a/al/filter.cpp b/al/filter.cpp
index f0a078b7..528d6059 100644
--- a/al/filter.cpp
+++ b/al/filter.cpp
@@ -49,19 +49,21 @@
namespace {
+using SubListAllocator = typename al::allocator<std::array<ALfilter,64>>;
+
class filter_exception final : public al::base_exception {
ALenum 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
filter_exception(ALenum code, const char *msg, ...);
~filter_exception() override;
- ALenum errorCode() const noexcept { return mErrorCode; }
+ [[nodiscard]] auto errorCode() const noexcept -> ALenum { return mErrorCode; }
};
filter_exception::filter_exception(ALenum code, const char* msg, ...) : mErrorCode{code}
@@ -80,36 +82,36 @@ void InitFilterParams(ALfilter *filter, ALenum type)
{
filter->Gain = AL_LOWPASS_DEFAULT_GAIN;
filter->GainHF = AL_LOWPASS_DEFAULT_GAINHF;
- filter->HFReference = LOWPASSFREQREF;
+ filter->HFReference = LowPassFreqRef;
filter->GainLF = 1.0f;
- filter->LFReference = HIGHPASSFREQREF;
+ filter->LFReference = HighPassFreqRef;
filter->mTypeVariant.emplace<LowpassFilterTable>();
}
else if(type == AL_FILTER_HIGHPASS)
{
filter->Gain = AL_HIGHPASS_DEFAULT_GAIN;
filter->GainHF = 1.0f;
- filter->HFReference = LOWPASSFREQREF;
+ filter->HFReference = LowPassFreqRef;
filter->GainLF = AL_HIGHPASS_DEFAULT_GAINLF;
- filter->LFReference = HIGHPASSFREQREF;
+ filter->LFReference = HighPassFreqRef;
filter->mTypeVariant.emplace<HighpassFilterTable>();
}
else if(type == AL_FILTER_BANDPASS)
{
filter->Gain = AL_BANDPASS_DEFAULT_GAIN;
filter->GainHF = AL_BANDPASS_DEFAULT_GAINHF;
- filter->HFReference = LOWPASSFREQREF;
+ filter->HFReference = LowPassFreqRef;
filter->GainLF = AL_BANDPASS_DEFAULT_GAINLF;
- filter->LFReference = HIGHPASSFREQREF;
+ filter->LFReference = HighPassFreqRef;
filter->mTypeVariant.emplace<BandpassFilterTable>();
}
else
{
filter->Gain = 1.0f;
filter->GainHF = 1.0f;
- filter->HFReference = LOWPASSFREQREF;
+ filter->HFReference = LowPassFreqRef;
filter->GainLF = 1.0f;
- filter->LFReference = HIGHPASSFREQREF;
+ filter->LFReference = HighPassFreqRef;
filter->mTypeVariant.emplace<NullFilterTable>();
}
filter->type = type;
@@ -121,21 +123,21 @@ bool EnsureFilters(ALCdevice *device, size_t needed)
[](size_t cur, const FilterSubList &sublist) noexcept -> size_t
{ return cur + static_cast<ALuint>(al::popcount(sublist.FreeMask)); })};
- while(needed > count)
- {
- if(device->FilterList.size() >= 1<<25) UNLIKELY
- return false;
-
- device->FilterList.emplace_back();
- auto sublist = device->FilterList.end() - 1;
- sublist->FreeMask = ~0_u64;
- sublist->Filters = static_cast<ALfilter*>(al_calloc(alignof(ALfilter), sizeof(ALfilter)*64));
- if(!sublist->Filters) UNLIKELY
+ try {
+ while(needed > count)
{
- device->FilterList.pop_back();
- return false;
+ if(device->FilterList.size() >= 1<<25) UNLIKELY
+ return false;
+
+ FilterSubList sublist{};
+ sublist.FreeMask = ~0_u64;
+ sublist.Filters = SubListAllocator{}.allocate(1);
+ device->FilterList.emplace_back(std::move(sublist));
+ count += 64;
}
- count += 64;
+ }
+ catch(...) {
+ return false;
}
return true;
}
@@ -150,7 +152,7 @@ ALfilter *AllocFilter(ALCdevice *device)
auto slidx = static_cast<ALuint>(al::countr_zero(sublist->FreeMask));
ASSUME(slidx < 64);
- ALfilter *filter{al::construct_at(sublist->Filters + slidx)};
+ ALfilter *filter{al::construct_at(al::to_address(sublist->Filters->begin() + slidx))};
InitFilterParams(filter, AL_FILTER_NULL);
/* Add 1 to avoid filter ID 0. */
@@ -185,7 +187,7 @@ inline ALfilter *LookupFilter(ALCdevice *device, ALuint id)
FilterSubList &sublist = device->FilterList[lidx];
if(sublist.FreeMask & (1_u64 << slidx)) UNLIKELY
return nullptr;
- return sublist.Filters + slidx;
+ return al::to_address(sublist.Filters->begin() + slidx);
}
} // namespace
@@ -695,10 +697,10 @@ FilterSubList::~FilterSubList()
while(usemask)
{
const int idx{al::countr_zero(usemask)};
- std::destroy_at(Filters+idx);
+ std::destroy_at(al::to_address(Filters->begin() + idx));
usemask &= ~(1_u64 << idx);
}
FreeMask = ~usemask;
- al_free(Filters);
+ SubListAllocator{}.deallocate(Filters, 1);
Filters = nullptr;
}
diff --git a/al/filter.h b/al/filter.h
index 505900d4..dffe8c6e 100644
--- a/al/filter.h
+++ b/al/filter.h
@@ -1,6 +1,8 @@
#ifndef AL_FILTER_H
#define AL_FILTER_H
+#include <array>
+#include <cstdint>
#include <string_view>
#include <variant>
@@ -9,10 +11,11 @@
#include "AL/alext.h"
#include "almalloc.h"
+#include "alnumeric.h"
-#define LOWPASSFREQREF 5000.0f
-#define HIGHPASSFREQREF 250.0f
+inline constexpr float LowPassFreqRef{5000.0f};
+inline constexpr float HighPassFreqRef{250.0f};
template<typename T>
struct FilterTable {
@@ -38,9 +41,9 @@ struct ALfilter {
float Gain{1.0f};
float GainHF{1.0f};
- float HFReference{LOWPASSFREQREF};
+ float HFReference{LowPassFreqRef};
float GainLF{1.0f};
- float LFReference{HIGHPASSFREQREF};
+ float LFReference{HighPassFreqRef};
using TableTypes = std::variant<NullFilterTable,LowpassFilterTable,HighpassFilterTable,
BandpassFilterTable>;
@@ -51,7 +54,22 @@ struct ALfilter {
static void SetName(ALCcontext *context, ALuint id, std::string_view name);
- DISABLE_ALLOC()
+ DISABLE_ALLOC
+};
+
+struct FilterSubList {
+ uint64_t FreeMask{~0_u64};
+ gsl::owner<std::array<ALfilter,64>*> Filters{nullptr};
+
+ 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; }
};
#endif
diff --git a/al/listener.h b/al/listener.h
index 81532877..a50f118a 100644
--- a/al/listener.h
+++ b/al/listener.h
@@ -18,7 +18,7 @@ struct ALlistener {
float Gain{1.0f};
float mMetersPerUnit{AL_DEFAULT_METERS_PER_UNIT};
- DISABLE_ALLOC()
+ DISABLE_ALLOC
};
#endif
diff --git a/al/source.cpp b/al/source.cpp
index fe5bba40..b3af9428 100644
--- a/al/source.cpp
+++ b/al/source.cpp
@@ -80,7 +80,7 @@
namespace {
-using namespace std::placeholders;
+using SubListAllocator = typename al::allocator<std::array<ALsource,64>>;
using std::chrono::nanoseconds;
using seconds_d = std::chrono::duration<double>;
@@ -171,7 +171,7 @@ void UpdateSourceProps(const ALsource *source, Voice *voice, ALCcontext *context
ret.LFReference = srcsend.LFReference;
return ret;
};
- std::transform(source->Send.cbegin(), source->Send.cend(), props->Send, copy_send);
+ std::transform(source->Send.cbegin(), source->Send.cend(), props->Send.begin(), copy_send);
if(!props->Send[0].Slot && context->mDefaultSlot)
props->Send[0].Slot = context->mDefaultSlot->mSlot;
@@ -202,7 +202,7 @@ int64_t GetSourceSampleOffset(ALsource *Source, ALCcontext *context, nanoseconds
do {
refcount = device->waitForMix();
- *clocktime = GetDeviceClockTime(device);
+ *clocktime = device->getClockTime();
voice = GetSourceVoice(Source, context);
if(voice)
{
@@ -212,7 +212,7 @@ int64_t GetSourceSampleOffset(ALsource *Source, ALCcontext *context, nanoseconds
readPos += voice->mPositionFrac.load(std::memory_order_relaxed);
}
std::atomic_thread_fence(std::memory_order_acquire);
- } while(refcount != device->MixCount.load(std::memory_order_relaxed));
+ } while(refcount != device->mMixCount.load(std::memory_order_relaxed));
if(!voice)
return 0;
@@ -242,7 +242,7 @@ double GetSourceSecOffset(ALsource *Source, ALCcontext *context, nanoseconds *cl
do {
refcount = device->waitForMix();
- *clocktime = GetDeviceClockTime(device);
+ *clocktime = device->getClockTime();
voice = GetSourceVoice(Source, context);
if(voice)
{
@@ -252,7 +252,7 @@ double GetSourceSecOffset(ALsource *Source, ALCcontext *context, nanoseconds *cl
readPos += voice->mPositionFrac.load(std::memory_order_relaxed);
}
std::atomic_thread_fence(std::memory_order_acquire);
- } while(refcount != device->MixCount.load(std::memory_order_relaxed));
+ } while(refcount != device->mMixCount.load(std::memory_order_relaxed));
if(!voice)
return 0.0f;
@@ -302,7 +302,7 @@ NOINLINE T GetSourceOffset(ALsource *Source, ALenum name, ALCcontext *context)
readPosFrac = voice->mPositionFrac.load(std::memory_order_relaxed);
}
std::atomic_thread_fence(std::memory_order_acquire);
- } while(refcount != device->MixCount.load(std::memory_order_relaxed));
+ } while(refcount != device->mMixCount.load(std::memory_order_relaxed));
if(!voice)
return T{0};
@@ -575,7 +575,7 @@ void SendVoiceChanges(ALCcontext *ctx, VoiceChange *tail)
oldhead->mNext.store(tail, std::memory_order_release);
const bool connected{device->Connected.load(std::memory_order_acquire)};
- device->waitForMix();
+ std::ignore = device->waitForMix();
if(!connected) UNLIKELY
{
if(ctx->mStopVoicesOnDisconnect.load(std::memory_order_acquire))
@@ -681,7 +681,7 @@ bool SetVoiceOffset(Voice *oldvoice, const VoicePos &vpos, ALsource *source, ALC
return true;
/* Otherwise, wait for any current mix to finish and check one last time. */
- device->waitForMix();
+ std::ignore = device->waitForMix();
if(newvoice->mPlayState.load(std::memory_order_acquire) != Voice::Pending)
return true;
/* The change-over failed because the old voice stopped before the new
@@ -721,21 +721,21 @@ bool EnsureSources(ALCcontext *context, size_t needed)
[](size_t cur, const SourceSubList &sublist) noexcept -> size_t
{ return cur + static_cast<ALuint>(al::popcount(sublist.FreeMask)); })};
- while(needed > count)
- {
- if(context->mSourceList.size() >= 1<<25) UNLIKELY
- return false;
-
- context->mSourceList.emplace_back();
- auto sublist = context->mSourceList.end() - 1;
- sublist->FreeMask = ~0_u64;
- sublist->Sources = static_cast<ALsource*>(al_calloc(alignof(ALsource), sizeof(ALsource)*64));
- if(!sublist->Sources) UNLIKELY
+ try {
+ while(needed > count)
{
- context->mSourceList.pop_back();
- return false;
+ if(context->mSourceList.size() >= 1<<25) UNLIKELY
+ return false;
+
+ SourceSubList sublist{};
+ sublist.FreeMask = ~0_u64;
+ sublist.Sources = SubListAllocator{}.allocate(1);
+ context->mSourceList.emplace_back(std::move(sublist));
+ count += 64;
}
- count += 64;
+ }
+ catch(...) {
+ return false;
}
return true;
}
@@ -749,7 +749,7 @@ ALsource *AllocSource(ALCcontext *context)
auto slidx = static_cast<ALuint>(al::countr_zero(sublist->FreeMask));
ASSUME(slidx < 64);
- ALsource *source{al::construct_at(sublist->Sources + slidx)};
+ ALsource *source{al::construct_at(al::to_address(sublist->Sources->begin() + slidx))};
/* Add 1 to avoid source ID 0. */
source->id = ((lidx<<6) | slidx) + 1;
@@ -797,7 +797,7 @@ inline ALsource *LookupSource(ALCcontext *context, ALuint id) noexcept
SourceSubList &sublist{context->mSourceList[lidx]};
if(sublist.FreeMask & (1_u64 << slidx)) UNLIKELY
return nullptr;
- return sublist.Sources + slidx;
+ return al::to_address(sublist.Sources->begin() + slidx);
}
auto LookupBuffer = [](ALCdevice *device, auto id) noexcept -> ALbuffer*
@@ -810,7 +810,7 @@ auto LookupBuffer = [](ALCdevice *device, auto id) noexcept -> ALbuffer*
BufferSubList &sublist = device->BufferList[static_cast<size_t>(lidx)];
if(sublist.FreeMask & (1_u64 << slidx)) UNLIKELY
return nullptr;
- return sublist.Buffers + static_cast<size_t>(slidx);
+ return al::to_address(sublist.Buffers->begin() + static_cast<size_t>(slidx));
};
auto LookupFilter = [](ALCdevice *device, auto id) noexcept -> ALfilter*
@@ -823,7 +823,7 @@ auto LookupFilter = [](ALCdevice *device, auto id) noexcept -> ALfilter*
FilterSubList &sublist = device->FilterList[static_cast<size_t>(lidx)];
if(sublist.FreeMask & (1_u64 << slidx)) UNLIKELY
return nullptr;
- return sublist.Filters + static_cast<size_t>(slidx);
+ return al::to_address(sublist.Filters->begin() + static_cast<size_t>(slidx));
};
auto LookupEffectSlot = [](ALCcontext *context, auto id) noexcept -> ALeffectslot*
@@ -836,7 +836,7 @@ auto LookupEffectSlot = [](ALCcontext *context, auto id) noexcept -> ALeffectslo
EffectSlotSubList &sublist{context->mEffectSlotList[static_cast<size_t>(lidx)]};
if(sublist.FreeMask & (1_u64 << slidx)) UNLIKELY
return nullptr;
- return sublist.EffectSlots + static_cast<size_t>(slidx);
+ return al::to_address(sublist.EffectSlots->begin() + static_cast<size_t>(slidx));
};
@@ -1316,11 +1316,11 @@ constexpr ALuint DoubleValsByProp(ALenum prop)
struct check_exception : std::exception {
};
struct check_size_exception final : check_exception {
- const char *what() const noexcept override
+ [[nodiscard]] auto what() const noexcept -> const char* override
{ return "check_size_exception"; }
};
struct check_value_exception final : check_exception {
- const char *what() const noexcept override
+ [[nodiscard]] auto what() const noexcept -> const char* override
{ return "check_value_exception"; }
};
@@ -1371,21 +1371,22 @@ struct PropType<ALfloat> { static const char *Name() { return "float"; } };
template<>
struct PropType<ALdouble> { static const char *Name() { return "double"; } };
-template<typename T>
struct HexPrinter {
- char mStr[sizeof(T)*2 + 3]{};
+ std::array<char,32> mStr{};
+
+ template<typename T>
HexPrinter(T value)
{
using ST = std::make_signed_t<std::remove_cv_t<T>>;
if constexpr(std::is_same_v<ST,int>)
- std::snprintf(mStr, std::size(mStr), "0x%x", value);
+ std::snprintf(mStr.data(), mStr.size(), "0x%x", value);
else if constexpr(std::is_same_v<ST,long>)
- std::snprintf(mStr, std::size(mStr), "0x%lx", value);
+ std::snprintf(mStr.data(), mStr.size(), "0x%lx", value);
else if constexpr(std::is_same_v<ST,long long>)
- std::snprintf(mStr, std::size(mStr), "0x%llx", value);
+ std::snprintf(mStr.data(), mStr.size(), "0x%llx", value);
}
- const char *c_str() const noexcept { return mStr; }
+ [[nodiscard]] auto c_str() const noexcept -> const char* { return mStr.data(); }
};
@@ -1579,7 +1580,7 @@ NOINLINE void SetProperty(ALsource *const Source, ALCcontext *const Context, con
* to ensure it isn't currently looping back or reaching the
* end.
*/
- device->waitForMix();
+ std::ignore = device->waitForMix();
}
return;
}
@@ -1604,10 +1605,11 @@ NOINLINE void SetProperty(ALsource *const Source, ALCcontext *const Context, con
if(!buffer) UNLIKELY
return Context->setError(AL_INVALID_VALUE, "Invalid buffer ID %s",
std::to_string(values[0]).c_str());
- if(buffer->MappedAccess && !(buffer->MappedAccess&AL_MAP_PERSISTENT_BIT_SOFT)) UNLIKELY
+ if(buffer->MappedAccess
+ && !(buffer->MappedAccess&AL_MAP_PERSISTENT_BIT_SOFT)) UNLIKELY
return Context->setError(AL_INVALID_OPERATION,
"Setting non-persistently mapped buffer %u", buffer->id);
- if(buffer->mCallback && ReadRef(buffer->ref) != 0) UNLIKELY
+ if(buffer->mCallback && buffer->ref.load(std::memory_order_relaxed) != 0) UNLIKELY
return Context->setError(AL_INVALID_OPERATION,
"Setting already-set callback buffer %u", buffer->id);
@@ -1793,9 +1795,9 @@ NOINLINE void SetProperty(ALsource *const Source, ALCcontext *const Context, con
{
Source->Direct.Gain = 1.0f;
Source->Direct.GainHF = 1.0f;
- Source->Direct.HFReference = LOWPASSFREQREF;
+ Source->Direct.HFReference = LowPassFreqRef;
Source->Direct.GainLF = 1.0f;
- Source->Direct.LFReference = HIGHPASSFREQREF;
+ Source->Direct.LFReference = HighPassFreqRef;
}
return UpdateSourceProps(Source, Context);
}
@@ -1921,7 +1923,8 @@ NOINLINE void SetProperty(ALsource *const Source, ALCcontext *const Context, con
ALeffectslot *slot{};
if(values[0])
{
- if((slot=LookupEffectSlot(Context, slotid)) == nullptr) UNLIKELY
+ slot = LookupEffectSlot(Context, slotid);
+ if(!slot) UNLIKELY
return Context->setError(AL_INVALID_VALUE, "Invalid effect ID %s",
std::to_string(slotid).c_str());
}
@@ -1950,9 +1953,9 @@ NOINLINE void SetProperty(ALsource *const Source, ALCcontext *const Context, con
/* Disable filter */
send.Gain = 1.0f;
send.GainHF = 1.0f;
- send.HFReference = LOWPASSFREQREF;
+ send.HFReference = LowPassFreqRef;
send.GainLF = 1.0f;
- send.LFReference = HIGHPASSFREQREF;
+ send.LFReference = HighPassFreqRef;
}
/* We must force an update if the current auxiliary slot is valid
@@ -3404,90 +3407,94 @@ FORCE_ALIGN void AL_APIENTRY alSourceQueueBuffersDirect(ALCcontext *context, ALu
std::unique_lock<std::mutex> buflock{device->BufferLock};
const size_t NewListStart{source->mQueue.size()};
- ALbufferQueueItem *BufferList{nullptr};
- for(ALsizei i{0};i < nb;i++)
- {
- bool fmt_mismatch{false};
- ALbuffer *buffer{nullptr};
- if(buffers[i] && (buffer=LookupBuffer(device, buffers[i])) == nullptr)
+ try {
+ ALbufferQueueItem *BufferList{nullptr};
+ for(ALsizei i{0};i < nb;i++)
{
- context->setError(AL_INVALID_NAME, "Queueing invalid buffer ID %u", buffers[i]);
- goto buffer_error;
- }
- if(buffer)
- {
- if(buffer->mSampleRate < 1)
+ bool fmt_mismatch{false};
+ ALbuffer *buffer{buffers[i] ? LookupBuffer(device, buffers[i]) : nullptr};
+ if(buffers[i] && !buffer)
{
- context->setError(AL_INVALID_OPERATION, "Queueing buffer %u with no format",
- buffer->id);
- goto buffer_error;
+ context->setError(AL_INVALID_NAME, "Queueing invalid buffer ID %u", buffers[i]);
+ throw std::exception{};
}
- if(buffer->mCallback)
+ if(buffer)
{
- context->setError(AL_INVALID_OPERATION, "Queueing callback buffer %u", buffer->id);
- goto buffer_error;
+ if(buffer->mSampleRate < 1)
+ {
+ context->setError(AL_INVALID_OPERATION, "Queueing buffer %u with no format",
+ buffer->id);
+ throw std::exception{};
+ }
+ if(buffer->mCallback)
+ {
+ context->setError(AL_INVALID_OPERATION, "Queueing callback buffer %u",
+ buffer->id);
+ throw std::exception{};
+ }
+ if(buffer->MappedAccess != 0 && !(buffer->MappedAccess&AL_MAP_PERSISTENT_BIT_SOFT))
+ {
+ context->setError(AL_INVALID_OPERATION,
+ "Queueing non-persistently mapped buffer %u", buffer->id);
+ throw std::exception{};
+ }
}
- if(buffer->MappedAccess != 0 && !(buffer->MappedAccess&AL_MAP_PERSISTENT_BIT_SOFT))
+
+ source->mQueue.emplace_back();
+ if(!BufferList)
+ BufferList = &source->mQueue.back();
+ else
{
- context->setError(AL_INVALID_OPERATION,
- "Queueing non-persistently mapped buffer %u", buffer->id);
- goto buffer_error;
+ auto &item = source->mQueue.back();
+ BufferList->mNext.store(&item, std::memory_order_relaxed);
+ BufferList = &item;
}
- }
-
- source->mQueue.emplace_back();
- if(!BufferList)
- BufferList = &source->mQueue.back();
- else
- {
- auto &item = source->mQueue.back();
- BufferList->mNext.store(&item, std::memory_order_relaxed);
- BufferList = &item;
- }
- if(!buffer) continue;
- BufferList->mBlockAlign = buffer->mBlockAlign;
- BufferList->mSampleLen = buffer->mSampleLen;
- BufferList->mLoopEnd = buffer->mSampleLen;
- BufferList->mSamples = buffer->mData.data();
- BufferList->mBuffer = buffer;
- IncrementRef(buffer->ref);
-
- if(BufferFmt == nullptr)
- BufferFmt = buffer;
- else
- {
- fmt_mismatch |= BufferFmt->mSampleRate != buffer->mSampleRate;
- fmt_mismatch |= BufferFmt->mChannels != buffer->mChannels;
- fmt_mismatch |= BufferFmt->mType != buffer->mType;
- if(BufferFmt->isBFormat())
+ if(!buffer) continue;
+ BufferList->mBlockAlign = buffer->mBlockAlign;
+ BufferList->mSampleLen = buffer->mSampleLen;
+ BufferList->mLoopEnd = buffer->mSampleLen;
+ BufferList->mSamples = buffer->mData.data();
+ BufferList->mBuffer = buffer;
+ IncrementRef(buffer->ref);
+
+ if(BufferFmt == nullptr)
+ BufferFmt = buffer;
+ else
{
- fmt_mismatch |= BufferFmt->mAmbiLayout != buffer->mAmbiLayout;
- fmt_mismatch |= BufferFmt->mAmbiScaling != buffer->mAmbiScaling;
+ fmt_mismatch |= BufferFmt->mSampleRate != buffer->mSampleRate;
+ fmt_mismatch |= BufferFmt->mChannels != buffer->mChannels;
+ fmt_mismatch |= BufferFmt->mType != buffer->mType;
+ if(BufferFmt->isBFormat())
+ {
+ fmt_mismatch |= BufferFmt->mAmbiLayout != buffer->mAmbiLayout;
+ fmt_mismatch |= BufferFmt->mAmbiScaling != buffer->mAmbiScaling;
+ }
+ fmt_mismatch |= BufferFmt->mAmbiOrder != buffer->mAmbiOrder;
}
- fmt_mismatch |= BufferFmt->mAmbiOrder != buffer->mAmbiOrder;
- }
- if(fmt_mismatch) UNLIKELY
- {
- context->setError(AL_INVALID_OPERATION, "Queueing buffer with mismatched format\n"
- " Expected: %uhz, %s, %s ; Got: %uhz, %s, %s\n", BufferFmt->mSampleRate,
- NameFromFormat(BufferFmt->mType), NameFromFormat(BufferFmt->mChannels),
- buffer->mSampleRate, NameFromFormat(buffer->mType),
- NameFromFormat(buffer->mChannels));
-
- buffer_error:
- /* A buffer failed (invalid ID or format), so unlock and release
- * each buffer we had.
- */
- auto iter = source->mQueue.begin() + ptrdiff_t(NewListStart);
- for(;iter != source->mQueue.end();++iter)
+ if(fmt_mismatch) UNLIKELY
{
- if(ALbuffer *buf{iter->mBuffer})
- DecrementRef(buf->ref);
+ context->setError(AL_INVALID_OPERATION, "Queueing buffer with mismatched format\n"
+ " Expected: %uhz, %s, %s ; Got: %uhz, %s, %s\n", BufferFmt->mSampleRate,
+ NameFromFormat(BufferFmt->mType), NameFromFormat(BufferFmt->mChannels),
+ buffer->mSampleRate, NameFromFormat(buffer->mType),
+ NameFromFormat(buffer->mChannels));
+ throw std::exception{};
}
- source->mQueue.resize(NewListStart);
- return;
}
}
+ catch(...) {
+ /* A buffer failed (invalid ID or format), or there was some other
+ * unexpected error, so unlock and release each buffer we had.
+ */
+ auto iter = source->mQueue.begin() + ptrdiff_t(NewListStart);
+ for(;iter != source->mQueue.end();++iter)
+ {
+ if(ALbuffer *buf{iter->mBuffer})
+ DecrementRef(buf->ref);
+ }
+ source->mQueue.resize(NewListStart);
+ return;
+ }
/* All buffers good. */
buflock.unlock();
@@ -3565,17 +3572,17 @@ ALsource::ALsource()
{
Direct.Gain = 1.0f;
Direct.GainHF = 1.0f;
- Direct.HFReference = LOWPASSFREQREF;
+ Direct.HFReference = LowPassFreqRef;
Direct.GainLF = 1.0f;
- Direct.LFReference = HIGHPASSFREQREF;
+ Direct.LFReference = HighPassFreqRef;
for(auto &send : Send)
{
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;
}
}
@@ -3632,18 +3639,15 @@ SourceSubList::~SourceSubList()
{
const int idx{al::countr_zero(usemask)};
usemask &= ~(1_u64 << idx);
- std::destroy_at(Sources+idx);
+ std::destroy_at(al::to_address(Sources->begin() + idx));
}
FreeMask = ~usemask;
- al_free(Sources);
+ SubListAllocator{}.deallocate(Sources, 1);
Sources = nullptr;
}
#ifdef ALSOFT_EAX
-constexpr const ALsource::EaxFxSlotIds ALsource::eax4_fx_slot_ids;
-constexpr const ALsource::EaxFxSlotIds ALsource::eax5_fx_slot_ids;
-
void ALsource::eaxInitialize(ALCcontext *context) noexcept
{
assert(context != nullptr);
@@ -3916,27 +3920,30 @@ void ALsource::eax4_translate(const Eax4Props& src, Eax5Props& dst) noexcept
// Active FX slots.
//
- for (auto i = 0; i < EAX50_MAX_ACTIVE_FXSLOTS; ++i) {
+ for(size_t i{0};i < EAX50_MAX_ACTIVE_FXSLOTS;++i)
+ {
auto& dst_id = dst.active_fx_slots.guidActiveFXSlots[i];
- if (i < EAX40_MAX_ACTIVE_FXSLOTS) {
+ if(i < EAX40_MAX_ACTIVE_FXSLOTS)
+ {
const auto& src_id = src.active_fx_slots.guidActiveFXSlots[i];
- if (src_id == EAX_NULL_GUID)
+ if(src_id == EAX_NULL_GUID)
dst_id = EAX_NULL_GUID;
- else if (src_id == EAX_PrimaryFXSlotID)
+ else if(src_id == EAX_PrimaryFXSlotID)
dst_id = EAX_PrimaryFXSlotID;
- else if (src_id == EAXPROPERTYID_EAX40_FXSlot0)
+ else if(src_id == EAXPROPERTYID_EAX40_FXSlot0)
dst_id = EAXPROPERTYID_EAX50_FXSlot0;
- else if (src_id == EAXPROPERTYID_EAX40_FXSlot1)
+ else if(src_id == EAXPROPERTYID_EAX40_FXSlot1)
dst_id = EAXPROPERTYID_EAX50_FXSlot1;
- else if (src_id == EAXPROPERTYID_EAX40_FXSlot2)
+ else if(src_id == EAXPROPERTYID_EAX40_FXSlot2)
dst_id = EAXPROPERTYID_EAX50_FXSlot2;
- else if (src_id == EAXPROPERTYID_EAX40_FXSlot3)
+ else if(src_id == EAXPROPERTYID_EAX40_FXSlot3)
dst_id = EAXPROPERTYID_EAX50_FXSlot3;
else
assert(false && "Unknown active FX slot ID.");
- } else
+ }
+ else
dst_id = EAX_NULL_GUID;
}
@@ -4067,9 +4074,9 @@ void ALsource::eax_update_direct_filter()
const auto& direct_param = eax_create_direct_filter_param();
Direct.Gain = direct_param.gain;
Direct.GainHF = direct_param.gain_hf;
- Direct.HFReference = LOWPASSFREQREF;
+ Direct.HFReference = LowPassFreqRef;
Direct.GainLF = 1.0f;
- Direct.LFReference = HIGHPASSFREQREF;
+ Direct.LFReference = HighPassFreqRef;
mPropsDirty = true;
}
@@ -4358,7 +4365,7 @@ void ALsource::eax4_set(const EaxCall& call, Eax4Props& props)
break;
case EAXSOURCE_ACTIVEFXSLOTID:
- eax4_defer_active_fx_slot_id(call, props.active_fx_slots.guidActiveFXSlots);
+ eax4_defer_active_fx_slot_id(call, al::span{props.active_fx_slots.guidActiveFXSlots});
break;
default:
@@ -4439,7 +4446,7 @@ void ALsource::eax5_set(const EaxCall& call, Eax5Props& props)
break;
case EAXSOURCE_ACTIVEFXSLOTID:
- eax5_defer_active_fx_slot_id(call, props.active_fx_slots.guidActiveFXSlots);
+ eax5_defer_active_fx_slot_id(call, al::span{props.active_fx_slots.guidActiveFXSlots});
break;
case EAXSOURCE_MACROFXFACTOR:
@@ -4729,7 +4736,8 @@ void ALsource::eax4_get(const EaxCall& call, const Eax4Props& props)
break;
case EAXSOURCE_ACTIVEFXSLOTID:
- eax_get_active_fx_slot_id(call, props.active_fx_slots.guidActiveFXSlots, EAX40_MAX_ACTIVE_FXSLOTS);
+ eax_get_active_fx_slot_id(call, props.active_fx_slots.guidActiveFXSlots.data(),
+ EAX40_MAX_ACTIVE_FXSLOTS);
break;
default:
@@ -4801,7 +4809,8 @@ void ALsource::eax5_get(const EaxCall& call, const Eax5Props& props)
break;
case EAXSOURCE_ACTIVEFXSLOTID:
- eax_get_active_fx_slot_id(call, props.active_fx_slots.guidActiveFXSlots, EAX50_MAX_ACTIVE_FXSLOTS);
+ eax_get_active_fx_slot_id(call, props.active_fx_slots.guidActiveFXSlots.data(),
+ EAX50_MAX_ACTIVE_FXSLOTS);
break;
case EAXSOURCE_MACROFXFACTOR:
@@ -4841,9 +4850,9 @@ void ALsource::eax_set_al_source_send(ALeffectslot *slot, size_t sendidx, const
auto &send = Send[sendidx];
send.Gain = filter.gain;
send.GainHF = filter.gain_hf;
- send.HFReference = LOWPASSFREQREF;
+ send.HFReference = LowPassFreqRef;
send.GainLF = 1.0f;
- send.LFReference = HIGHPASSFREQREF;
+ send.LFReference = HighPassFreqRef;
if(slot != nullptr)
IncrementRef(slot->ref);
diff --git a/al/source.h b/al/source.h
index c7694f83..84fd7664 100644
--- a/al/source.h
+++ b/al/source.h
@@ -4,6 +4,7 @@
#include <array>
#include <atomic>
#include <cstddef>
+#include <cstdint>
#include <deque>
#include <iterator>
#include <limits>
@@ -37,7 +38,7 @@ enum class SourceStereo : bool {
Enhanced = AL_SUPER_STEREO_SOFT
};
-#define DEFAULT_SENDS 2
+inline constexpr size_t DefaultSendCount{2};
inline constexpr ALuint InvalidVoiceIndex{std::numeric_limits<ALuint>::max()};
@@ -46,7 +47,7 @@ inline bool sBufferSubDataCompat{false};
struct ALbufferQueueItem : public VoiceBufferItem {
ALbuffer *mBuffer{nullptr};
- DISABLE_ALLOC()
+ DISABLE_ALLOC
};
@@ -108,21 +109,21 @@ struct ALsource {
/** Direct filter and auxiliary send info. */
struct {
- float Gain;
- float GainHF;
- float HFReference;
- float GainLF;
- float LFReference;
+ float Gain{};
+ float GainHF{};
+ float HFReference{};
+ float GainLF{};
+ float LFReference{};
} Direct;
struct SendData {
- ALeffectslot *Slot;
- float Gain;
- float GainHF;
- float HFReference;
- float GainLF;
- float LFReference;
+ ALeffectslot *Slot{};
+ float Gain{};
+ float GainHF{};
+ float HFReference{};
+ float GainLF{};
+ float LFReference{};
};
- std::array<SendData,MAX_SENDS> Send;
+ std::array<SendData,MaxSendCount> Send;
/**
* Last user-specified offset, and the offset type (bytes, samples, or
@@ -159,7 +160,7 @@ struct ALsource {
static void SetName(ALCcontext *context, ALuint id, std::string_view name);
- DISABLE_ALLOC()
+ DISABLE_ALLOC
#ifdef ALSOFT_EAX
public:
@@ -173,18 +174,18 @@ public:
private:
using Exception = EaxSourceException;
- static constexpr auto eax_max_speakers = 9;
+ static constexpr auto eax_max_speakers{9u};
- using EaxFxSlotIds = const GUID* [EAX_MAX_FXSLOTS];
+ using EaxFxSlotIds = std::array<const GUID*,EAX_MAX_FXSLOTS>;
- static constexpr const EaxFxSlotIds eax4_fx_slot_ids = {
+ static constexpr const EaxFxSlotIds eax4_fx_slot_ids{
&EAXPROPERTYID_EAX40_FXSlot0,
&EAXPROPERTYID_EAX40_FXSlot1,
&EAXPROPERTYID_EAX40_FXSlot2,
&EAXPROPERTYID_EAX40_FXSlot3,
};
- static constexpr const EaxFxSlotIds eax5_fx_slot_ids = {
+ static constexpr const EaxFxSlotIds eax5_fx_slot_ids{
&EAXPROPERTYID_EAX50_FXSlot0,
&EAXPROPERTYID_EAX50_FXSlot1,
&EAXPROPERTYID_EAX50_FXSlot2,
@@ -839,11 +840,10 @@ private:
float path_ratio,
float lf_ratio) noexcept;
- EaxAlLowPassParam eax_create_direct_filter_param() const noexcept;
+ [[nodiscard]] auto eax_create_direct_filter_param() const noexcept -> EaxAlLowPassParam;
- EaxAlLowPassParam eax_create_room_filter_param(
- const ALeffectslot& fx_slot,
- const EAXSOURCEALLSENDPROPERTIES& send) const noexcept;
+ [[nodiscard]] auto eax_create_room_filter_param(const ALeffectslot& fx_slot,
+ const EAXSOURCEALLSENDPROPERTIES& send) const noexcept -> EaxAlLowPassParam;
void eax_update_direct_filter();
void eax_update_room_filters();
@@ -978,21 +978,21 @@ private:
}
template<typename TValidator, size_t TIdCount>
- void eax_defer_active_fx_slot_id(const EaxCall& call, GUID (&dst_ids)[TIdCount])
+ void eax_defer_active_fx_slot_id(const EaxCall& call, const al::span<GUID,TIdCount> dst_ids)
{
const auto src_ids = call.get_values<const GUID>(TIdCount);
std::for_each(src_ids.cbegin(), src_ids.cend(), TValidator{});
- std::uninitialized_copy(src_ids.cbegin(), src_ids.cend(), dst_ids);
+ std::uninitialized_copy(src_ids.cbegin(), src_ids.cend(), dst_ids.begin());
}
template<size_t TIdCount>
- void eax4_defer_active_fx_slot_id(const EaxCall& call, GUID (&dst_ids)[TIdCount])
+ void eax4_defer_active_fx_slot_id(const EaxCall& call, const al::span<GUID,TIdCount> dst_ids)
{
eax_defer_active_fx_slot_id<Eax4ActiveFxSlotIdValidator>(call, dst_ids);
}
template<size_t TIdCount>
- void eax5_defer_active_fx_slot_id(const EaxCall& call, GUID (&dst_ids)[TIdCount])
+ void eax5_defer_active_fx_slot_id(const EaxCall& call, const al::span<GUID,TIdCount> dst_ids)
{
eax_defer_active_fx_slot_id<Eax5ActiveFxSlotIdValidator>(call, dst_ids);
}
@@ -1043,4 +1043,19 @@ private:
void UpdateAllSourceProps(ALCcontext *context);
+struct SourceSubList {
+ uint64_t FreeMask{~0_u64};
+ gsl::owner<std::array<ALsource,64>*> Sources{nullptr};
+
+ 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; }
+};
+
#endif
diff --git a/al/state.cpp b/al/state.cpp
index 5131edd9..3ef87fbb 100644
--- a/al/state.cpp
+++ b/al/state.cpp
@@ -60,6 +60,7 @@
namespace {
+/* NOLINTBEGIN(*-avoid-c-arrays) */
constexpr ALchar alVendor[] = "OpenAL Community";
constexpr ALchar alVersion[] = "1.1 ALSOFT " ALSOFT_VERSION;
constexpr ALchar alRenderer[] = "OpenAL Soft";
@@ -73,6 +74,7 @@ constexpr ALchar alErrInvalidOp[] = "Invalid Operation";
constexpr ALchar alErrOutOfMemory[] = "Out of Memory";
constexpr ALchar alStackOverflow[] = "Stack Overflow";
constexpr ALchar alStackUnderflow[] = "Stack Underflow";
+/* NOLINTEND(*-avoid-c-arrays) */
/* Resampler strings */
template<Resampler rtype> struct ResamplerName { };
@@ -299,7 +301,7 @@ inline void UpdateProps(ALCcontext *context)
/* WARNING: Non-standard export! Not part of any extension, or exposed in the
* alcFunctions list.
*/
-AL_API const ALchar* AL_APIENTRY alsoft_get_version(void) noexcept
+AL_API auto AL_APIENTRY alsoft_get_version() noexcept -> const ALchar*
{
static const auto spoof = al::getenv("ALSOFT_SPOOF_VERSION");
if(spoof) return spoof->c_str();
@@ -386,7 +388,7 @@ FORCE_ALIGN ALboolean AL_APIENTRY alIsEnabledDirect(ALCcontext *context, ALenum
}
#define DECL_GETFUNC(R, Name, Ext) \
-AL_API R AL_APIENTRY Name##Ext(ALenum pname) noexcept \
+AL_API auto AL_APIENTRY Name##Ext(ALenum pname) noexcept -> R \
{ \
R value{}; \
auto context = GetContextRef(); \
@@ -394,7 +396,7 @@ AL_API R AL_APIENTRY Name##Ext(ALenum pname) noexcept \
Name##vDirect##Ext(GetContextRef().get(), pname, &value); \
return value; \
} \
-FORCE_ALIGN R AL_APIENTRY Name##Direct##Ext(ALCcontext *context, ALenum pname) noexcept \
+FORCE_ALIGN auto AL_APIENTRY Name##Direct##Ext(ALCcontext *context, ALenum pname) noexcept -> R \
{ \
R value{}; \
Name##vDirect##Ext(context, pname, &value); \
@@ -461,7 +463,7 @@ FORCE_ALIGN void AL_APIENTRY alGetPointervDirectSOFT(ALCcontext *context, ALenum
switch(pname)
{
case AL_EVENT_CALLBACK_FUNCTION_SOFT:
- *values = al::bit_cast<void*>(context->mEventCb);
+ *values = reinterpret_cast<void*>(context->mEventCb);
break;
case AL_EVENT_CALLBACK_USER_PARAM_SOFT:
@@ -469,7 +471,7 @@ FORCE_ALIGN void AL_APIENTRY alGetPointervDirectSOFT(ALCcontext *context, ALenum
break;
case AL_DEBUG_CALLBACK_FUNCTION_EXT:
- *values = al::bit_cast<void*>(context->mDebugCb);
+ *values = reinterpret_cast<void*>(context->mDebugCb);
break;
case AL_DEBUG_CALLBACK_USER_PARAM_EXT:
@@ -641,18 +643,18 @@ AL_API void AL_APIENTRY alDopplerVelocity(ALfloat value) noexcept
void UpdateContextProps(ALCcontext *context)
{
- /* Get an unused proprty container, or allocate a new one as needed. */
+ /* Get an unused property container, or allocate a new one as needed. */
ContextProps *props{context->mFreeContextProps.load(std::memory_order_acquire)};
if(!props)
- props = new ContextProps{};
- else
{
- ContextProps *next;
- do {
- next = props->next.load(std::memory_order_relaxed);
- } while(context->mFreeContextProps.compare_exchange_weak(props, next,
- std::memory_order_seq_cst, std::memory_order_acquire) == 0);
+ context->allocContextProps();
+ props = context->mFreeContextProps.load(std::memory_order_acquire);
}
+ ContextProps *next;
+ do {
+ next = props->next.load(std::memory_order_relaxed);
+ } while(context->mFreeContextProps.compare_exchange_weak(props, next,
+ std::memory_order_acq_rel, std::memory_order_acquire) == false);
/* Copy in current property values. */
ALlistener &listener = context->mListener;
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;
diff --git a/alsoftrc.sample b/alsoftrc.sample
index 42802184..278d78e5 100644
--- a/alsoftrc.sample
+++ b/alsoftrc.sample
@@ -406,7 +406,7 @@
# Renders samples directly in the real-time processing callback. This allows
# for lower latency and less overall CPU utilization, but can increase the
# risk of underruns when increasing the amount of work the mixer needs to do.
-#rt-mix = true
+#rt-mix = false
##
## PulseAudio backend stuff
diff --git a/common/albit.h b/common/albit.h
index 82a4a00d..d54a189c 100644
--- a/common/albit.h
+++ b/common/albit.h
@@ -1,6 +1,7 @@
#ifndef AL_BIT_H
#define AL_BIT_H
+#include <array>
#include <cstdint>
#include <cstring>
#include <limits>
@@ -17,9 +18,9 @@ std::enable_if_t<sizeof(To) == sizeof(From) && std::is_trivially_copyable_v<From
&& std::is_trivially_copyable_v<To>,
To> bit_cast(const From &src) noexcept
{
- alignas(To) char dst[sizeof(To)];
- std::memcpy(&dst[0], &src, sizeof(To));
- return *std::launder(reinterpret_cast<To*>(&dst[0]));
+ alignas(To) std::array<char,sizeof(To)> dst;
+ std::memcpy(dst.data(), &src, sizeof(To));
+ return *std::launder(reinterpret_cast<To*>(dst.data()));
}
#ifdef __BYTE_ORDER__
diff --git a/common/alcomplex.cpp b/common/alcomplex.cpp
index 82a0c43c..f2de5f51 100644
--- a/common/alcomplex.cpp
+++ b/common/alcomplex.cpp
@@ -155,6 +155,8 @@ void complex_fft(const al::span<std::complex<double>> buffer, const double sign)
}
else
{
+ assert(log2_size < 32);
+
for(size_t idx{1u};idx < fftsize-1;++idx)
{
size_t revidx{idx};
diff --git a/common/almalloc.cpp b/common/almalloc.cpp
deleted file mode 100644
index ad1dc6be..00000000
--- a/common/almalloc.cpp
+++ /dev/null
@@ -1,61 +0,0 @@
-
-#include "config.h"
-
-#include "almalloc.h"
-
-#include <cassert>
-#include <cstddef>
-#include <cstdlib>
-#include <cstring>
-#include <memory>
-#ifdef HAVE_MALLOC_H
-#include <malloc.h>
-#endif
-
-
-void *al_malloc(size_t alignment, size_t size)
-{
- assert((alignment & (alignment-1)) == 0);
- alignment = std::max(alignment, alignof(std::max_align_t));
-
-#if defined(HAVE_POSIX_MEMALIGN)
- void *ret{};
- if(posix_memalign(&ret, alignment, size) == 0)
- return ret;
- return nullptr;
-#elif defined(HAVE__ALIGNED_MALLOC)
- return _aligned_malloc(size, alignment);
-#else
- size_t total_size{size + alignment-1 + sizeof(void*)};
- void *base{std::malloc(total_size)};
- if(base != nullptr)
- {
- void *aligned_ptr{static_cast<char*>(base) + sizeof(void*)};
- total_size -= sizeof(void*);
-
- std::align(alignment, size, aligned_ptr, total_size);
- *(static_cast<void**>(aligned_ptr)-1) = base;
- base = aligned_ptr;
- }
- return base;
-#endif
-}
-
-void *al_calloc(size_t alignment, size_t size)
-{
- void *ret{al_malloc(alignment, size)};
- if(ret) std::memset(ret, 0, size);
- return ret;
-}
-
-void al_free(void *ptr) noexcept
-{
-#if defined(HAVE_POSIX_MEMALIGN)
- std::free(ptr);
-#elif defined(HAVE__ALIGNED_MALLOC)
- _aligned_free(ptr);
-#else
- if(ptr != nullptr)
- std::free(*(static_cast<void**>(ptr) - 1));
-#endif
-}
diff --git a/common/almalloc.h b/common/almalloc.h
index 873473ca..3b9965e6 100644
--- a/common/almalloc.h
+++ b/common/almalloc.h
@@ -13,39 +13,17 @@
#include "pragmadefs.h"
-void al_free(void *ptr) noexcept;
-[[gnu::alloc_align(1), gnu::alloc_size(2), gnu::malloc]]
-void *al_malloc(size_t alignment, size_t size);
-[[gnu::alloc_align(1), gnu::alloc_size(2), gnu::malloc]]
-void *al_calloc(size_t alignment, size_t size);
+namespace gsl {
+template<typename T> using owner = T;
+};
-#define DISABLE_ALLOC() \
+#define DISABLE_ALLOC \
void *operator new(size_t) = delete; \
void *operator new[](size_t) = delete; \
void operator delete(void*) noexcept = delete; \
void operator delete[](void*) noexcept = delete;
-#define DEF_NEWDEL(T) \
- void *operator new(size_t size) \
- { \
- static_assert(&operator new == &T::operator new, \
- "Incorrect container type specified"); \
- if(void *ret{al_malloc(alignof(T), size)}) \
- return ret; \
- throw std::bad_alloc(); \
- } \
- void *operator new[](size_t size) { return operator new(size); } \
- void operator delete(void *block) noexcept { al_free(block); } \
- void operator delete[](void *block) noexcept { operator delete(block); }
-
-#define DEF_PLACE_NEWDEL() \
- void *operator new(size_t /*size*/, void *ptr) noexcept { return ptr; } \
- void *operator new[](size_t /*size*/, void *ptr) noexcept { return ptr; } \
- void operator delete(void *block, void*) noexcept { al_free(block); } \
- void operator delete(void *block) noexcept { al_free(block); } \
- void operator delete[](void *block, void*) noexcept { al_free(block); } \
- void operator delete[](void *block) noexcept { al_free(block); }
enum FamCount : size_t { };
@@ -58,54 +36,59 @@ enum FamCount : size_t { };
sizeof(T)); \
} \
\
- void *operator new(size_t /*size*/, FamCount count) \
+ gsl::owner<void*> operator new(size_t /*size*/, FamCount count) \
{ \
- if(void *ret{al_malloc(alignof(T), T::Sizeof(count))}) \
- return ret; \
- throw std::bad_alloc(); \
+ const auto alignment = std::align_val_t{alignof(T)}; \
+ return ::operator new[](T::Sizeof(count), alignment); \
} \
+ void operator delete(gsl::owner<void*> block, FamCount) noexcept \
+ { ::operator delete[](block, std::align_val_t{alignof(T)}); } \
+ void operator delete(gsl::owner<void*> block) noexcept \
+ { ::operator delete[](block, std::align_val_t{alignof(T)}); } \
void *operator new[](size_t /*size*/) = delete; \
- void operator delete(void *block, FamCount) { al_free(block); } \
- void operator delete(void *block) noexcept { al_free(block); } \
void operator delete[](void* /*block*/) = delete;
namespace al {
-template<typename T, std::size_t Align=alignof(T)>
+template<typename T, std::size_t AlignV=alignof(T)>
struct allocator {
- static constexpr std::size_t alignment{std::max(Align, alignof(T))};
-
- using value_type = T;
- using reference = T&;
- using const_reference = const T&;
- using pointer = T*;
- using const_pointer = const T*;
+ static constexpr auto Alignment = std::max(AlignV, alignof(T));
+ static constexpr auto AlignVal = std::align_val_t{Alignment};
+
+ using value_type = std::remove_cv_t<std::remove_reference_t<T>>;
+ using reference = value_type&;
+ using const_reference = const value_type&;
+ using pointer = value_type*;
+ using const_pointer = const value_type*;
using size_type = std::size_t;
using difference_type = std::ptrdiff_t;
using is_always_equal = std::true_type;
- template<typename U>
+ template<typename U, std::enable_if_t<alignof(U) <= Alignment,bool> = true>
struct rebind {
- using other = allocator<U, Align>;
+ using other = allocator<U,Alignment>;
};
constexpr explicit allocator() noexcept = default;
template<typename U, std::size_t N>
- constexpr explicit allocator(const allocator<U,N>&) noexcept { }
+ constexpr explicit allocator(const allocator<U,N>&) noexcept
+ { static_assert(Alignment == allocator<U,N>::Alignment); }
- T *allocate(std::size_t n)
+ gsl::owner<T*> allocate(std::size_t n)
{
if(n > std::numeric_limits<std::size_t>::max()/sizeof(T)) throw std::bad_alloc();
- if(auto p = al_malloc(alignment, n*sizeof(T))) return static_cast<T*>(p);
- throw std::bad_alloc();
+ return static_cast<gsl::owner<T*>>(::operator new[](n*sizeof(T), AlignVal));
}
- void deallocate(T *p, std::size_t) noexcept { al_free(p); }
+ void deallocate(gsl::owner<T*> p, std::size_t) noexcept
+ { ::operator delete[](gsl::owner<void*>{p}, AlignVal); }
};
template<typename T, std::size_t N, typename U, std::size_t M>
-constexpr bool operator==(const allocator<T,N>&, const allocator<U,M>&) noexcept { return true; }
+constexpr bool operator==(const allocator<T,N>&, const allocator<U,M>&) noexcept
+{ return allocator<T,N>::Alignment == allocator<U,M>::Alignment; }
template<typename T, std::size_t N, typename U, std::size_t M>
-constexpr bool operator!=(const allocator<T,N>&, const allocator<U,M>&) noexcept { return false; }
+constexpr bool operator!=(const allocator<T,N>&, const allocator<U,M>&) noexcept
+{ return allocator<T,N>::Alignment != allocator<U,M>::Alignment; }
template<typename T>
@@ -124,124 +107,15 @@ constexpr auto to_address(const T &p) noexcept
template<typename T, typename ...Args>
constexpr T* construct_at(T *ptr, Args&& ...args)
- noexcept(std::is_nothrow_constructible<T, Args...>::value)
-{ return ::new(static_cast<void*>(ptr)) T{std::forward<Args>(args)...}; }
-
-
-/* Storage for flexible array data. This is trivially destructible if type T is
- * trivially destructible.
- */
-template<typename T, size_t alignment, bool = std::is_trivially_destructible<T>::value>
-struct FlexArrayStorage {
- const size_t mSize;
- union {
- char mDummy;
- alignas(alignment) T mArray[1];
- };
-
- static constexpr size_t Sizeof(size_t count, size_t base=0u) noexcept
- {
- const size_t len{sizeof(T)*count};
- return std::max(offsetof(FlexArrayStorage,mArray)+len, sizeof(FlexArrayStorage)) + base;
- }
-
- FlexArrayStorage(size_t size) : mSize{size}
- { std::uninitialized_default_construct_n(mArray, mSize); }
- ~FlexArrayStorage() = default;
-
- FlexArrayStorage(const FlexArrayStorage&) = delete;
- FlexArrayStorage& operator=(const FlexArrayStorage&) = delete;
-};
-
-template<typename T, size_t alignment>
-struct FlexArrayStorage<T,alignment,false> {
- const size_t mSize;
- union {
- char mDummy;
- alignas(alignment) T mArray[1];
- };
-
- static constexpr size_t Sizeof(size_t count, size_t base) noexcept
- {
- const size_t len{sizeof(T)*count};
- return std::max(offsetof(FlexArrayStorage,mArray)+len, sizeof(FlexArrayStorage)) + base;
- }
-
- FlexArrayStorage(size_t size) : mSize{size}
- { std::uninitialized_default_construct_n(mArray, mSize); }
- ~FlexArrayStorage() { std::destroy_n(mArray, mSize); }
-
- FlexArrayStorage(const FlexArrayStorage&) = delete;
- FlexArrayStorage& operator=(const FlexArrayStorage&) = delete;
-};
-
-/* A flexible array type. Used either standalone or at the end of a parent
- * struct, with placement new, to have a run-time-sized array that's embedded
- * with its size.
- */
-template<typename T, size_t alignment=alignof(T)>
-struct FlexArray {
- using element_type = T;
- using value_type = std::remove_cv_t<T>;
- using index_type = size_t;
- using difference_type = ptrdiff_t;
-
- using pointer = T*;
- using const_pointer = const T*;
- using reference = T&;
- using const_reference = const T&;
-
- using iterator = pointer;
- using const_iterator = const_pointer;
- using reverse_iterator = std::reverse_iterator<iterator>;
- using const_reverse_iterator = std::reverse_iterator<const_iterator>;
-
- using Storage_t_ = FlexArrayStorage<element_type,alignment>;
-
- Storage_t_ mStore;
-
- static constexpr index_type Sizeof(index_type count, index_type base=0u) noexcept
- { return Storage_t_::Sizeof(count, base); }
- static std::unique_ptr<FlexArray> Create(index_type count)
- {
- void *ptr{al_calloc(alignof(FlexArray), Sizeof(count))};
- return std::unique_ptr<FlexArray>{al::construct_at(static_cast<FlexArray*>(ptr), count)};
- }
-
- FlexArray(index_type size) : mStore{size} { }
- ~FlexArray() = default;
-
- index_type size() const noexcept { return mStore.mSize; }
- bool empty() const noexcept { return mStore.mSize == 0; }
-
- pointer data() noexcept { return mStore.mArray; }
- const_pointer data() const noexcept { return mStore.mArray; }
-
- reference operator[](index_type i) noexcept { return mStore.mArray[i]; }
- const_reference operator[](index_type i) const noexcept { return mStore.mArray[i]; }
-
- reference front() noexcept { return mStore.mArray[0]; }
- const_reference front() const noexcept { return mStore.mArray[0]; }
-
- reference back() noexcept { return mStore.mArray[mStore.mSize-1]; }
- const_reference back() const noexcept { return mStore.mArray[mStore.mSize-1]; }
-
- iterator begin() noexcept { return mStore.mArray; }
- const_iterator begin() const noexcept { return mStore.mArray; }
- const_iterator cbegin() const noexcept { return mStore.mArray; }
- iterator end() noexcept { return mStore.mArray + mStore.mSize; }
- const_iterator end() const noexcept { return mStore.mArray + mStore.mSize; }
- const_iterator cend() const noexcept { return mStore.mArray + mStore.mSize; }
-
- reverse_iterator rbegin() noexcept { return end(); }
- const_reverse_iterator rbegin() const noexcept { return end(); }
- const_reverse_iterator crbegin() const noexcept { return cend(); }
- reverse_iterator rend() noexcept { return begin(); }
- const_reverse_iterator rend() const noexcept { return begin(); }
- const_reverse_iterator crend() const noexcept { return cbegin(); }
-
- DEF_PLACE_NEWDEL()
-};
+ noexcept(std::is_nothrow_constructible_v<T, Args...>)
+{
+ /* NOLINTBEGIN(cppcoreguidelines-owning-memory) construct_at doesn't
+ * necessarily handle the address from an owner, while placement new
+ * expects to.
+ */
+ return ::new(static_cast<void*>(ptr)) T{std::forward<Args>(args)...};
+ /* NOLINTEND(cppcoreguidelines-owning-memory) */
+}
} // namespace al
diff --git a/common/alnumbers.h b/common/alnumbers.h
index e92d7b87..7abe6b32 100644
--- a/common/alnumbers.h
+++ b/common/alnumbers.h
@@ -3,9 +3,7 @@
#include <utility>
-namespace al {
-
-namespace numbers {
+namespace al::numbers {
namespace detail_ {
template<typename T>
@@ -29,8 +27,6 @@ inline constexpr auto inv_pi = inv_pi_v<double>;
inline constexpr auto sqrt2 = sqrt2_v<double>;
inline constexpr auto sqrt3 = sqrt3_v<double>;
-} // namespace numbers
-
-} // namespace al
+} // namespace al::numbers
#endif /* COMMON_ALNUMBERS_H */
diff --git a/common/alnumeric.h b/common/alnumeric.h
index 6281b012..cb8704b2 100644
--- a/common/alnumeric.h
+++ b/common/alnumeric.h
@@ -245,7 +245,7 @@ inline float fast_roundf(float f) noexcept
/* Integral limit, where sub-integral precision is not available for
* floats.
*/
- static constexpr float ilim[2]{
+ static constexpr std::array ilim{
8388608.0f /* 0x1.0p+23 */,
-8388608.0f /* -0x1.0p+23 */
};
diff --git a/common/alsem.h b/common/alsem.h
index 9f72d1c6..90b39319 100644
--- a/common/alsem.h
+++ b/common/alsem.h
@@ -24,7 +24,7 @@ class semaphore {
#else
using native_type = sem_t;
#endif
- native_type mSem;
+ native_type mSem{};
public:
semaphore(unsigned int initial=0);
diff --git a/common/alspan.h b/common/alspan.h
index 341ce7c8..822915da 100644
--- a/common/alspan.h
+++ b/common/alspan.h
@@ -5,6 +5,7 @@
#include <cstddef>
#include <initializer_list>
#include <iterator>
+#include <stdexcept>
#include <type_traits>
#include "almalloc.h"
@@ -12,7 +13,7 @@
namespace al {
-constexpr size_t dynamic_extent{static_cast<size_t>(-1)};
+inline constexpr size_t dynamic_extent{static_cast<size_t>(-1)};
template<typename T, size_t E=dynamic_extent>
class span;
@@ -23,31 +24,31 @@ namespace detail_ {
template<typename T, size_t E>
struct is_span_<span<T,E>> : std::true_type { };
template<typename T>
- constexpr bool is_span_v = is_span_<std::remove_cv_t<T>>::value;
+ inline constexpr bool is_span_v = is_span_<std::remove_cv_t<T>>::value;
template<typename T>
struct is_std_array_ : std::false_type { };
template<typename T, size_t N>
struct is_std_array_<std::array<T,N>> : std::true_type { };
template<typename T>
- constexpr bool is_std_array_v = is_std_array_<std::remove_cv_t<T>>::value;
+ inline constexpr bool is_std_array_v = is_std_array_<std::remove_cv_t<T>>::value;
template<typename T, typename = void>
- constexpr bool has_size_and_data = false;
+ inline constexpr bool has_size_and_data = false;
template<typename T>
- constexpr bool has_size_and_data<T,
+ inline constexpr bool has_size_and_data<T,
std::void_t<decltype(std::size(std::declval<T>())),decltype(std::data(std::declval<T>()))>>
= true;
template<typename C>
- constexpr bool is_valid_container_type = !is_span_v<C> && !is_std_array_v<C>
+ inline constexpr bool is_valid_container_type = !is_span_v<C> && !is_std_array_v<C>
&& !std::is_array<C>::value && has_size_and_data<C>;
template<typename T, typename U>
- constexpr bool is_array_compatible = std::is_convertible<T(*)[],U(*)[]>::value;
+ inline constexpr bool is_array_compatible = std::is_convertible<T(*)[],U(*)[]>::value; /* NOLINT(*-avoid-c-arrays) */
template<typename C, typename T>
- constexpr bool is_valid_container = is_valid_container_type<C>
+ inline constexpr bool is_valid_container = is_valid_container_type<C>
&& is_array_compatible<std::remove_pointer_t<decltype(std::data(std::declval<C&>()))>,T>;
} // namespace detail_
@@ -79,9 +80,9 @@ public:
constexpr explicit span(U iter, index_type) : mData{::al::to_address(iter)} { }
template<typename U, typename V, REQUIRES(!std::is_convertible<V,size_t>::value)>
constexpr explicit span(U first, V) : mData{::al::to_address(first)}
- {}
+ { }
- constexpr span(type_identity_t<element_type> (&arr)[E]) noexcept
+ constexpr span(type_identity_t<element_type> (&arr)[E]) noexcept /* NOLINT(*-avoid-c-arrays) */
: span{std::data(arr), std::size(arr)}
{ }
constexpr span(std::array<value_type,E> &arr) noexcept
@@ -107,43 +108,43 @@ public:
constexpr span& operator=(const span &rhs) noexcept = default;
- constexpr reference front() const { return *mData; }
- constexpr reference back() const { return *(mData+E-1); }
- constexpr reference operator[](index_type idx) const { return mData[idx]; }
- constexpr pointer data() const noexcept { return mData; }
+ [[nodiscard]] constexpr auto front() const -> reference { return mData[0]; }
+ [[nodiscard]] constexpr auto back() const -> reference { return mData[E-1]; }
+ [[nodiscard]] constexpr auto operator[](index_type idx) const -> reference { return mData[idx]; }
+ [[nodiscard]] constexpr auto data() const noexcept -> pointer { return mData; }
- constexpr index_type size() const noexcept { return E; }
- constexpr index_type size_bytes() const noexcept { return E * sizeof(value_type); }
- constexpr bool empty() const noexcept { return E == 0; }
+ [[nodiscard]] constexpr auto size() const noexcept -> index_type { return E; }
+ [[nodiscard]] constexpr auto size_bytes() const noexcept -> index_type { return E * sizeof(value_type); }
+ [[nodiscard]] constexpr auto empty() const noexcept -> bool { return E == 0; }
- constexpr iterator begin() const noexcept { return mData; }
- constexpr iterator end() const noexcept { return mData+E; }
- constexpr const_iterator cbegin() const noexcept { return mData; }
- constexpr const_iterator cend() const noexcept { return mData+E; }
+ [[nodiscard]] constexpr auto begin() const noexcept -> iterator { return mData; }
+ [[nodiscard]] constexpr auto end() const noexcept -> iterator { return mData+E; }
+ [[nodiscard]] constexpr auto cbegin() const noexcept -> const_iterator { return mData; }
+ [[nodiscard]] constexpr auto cend() const noexcept -> const_iterator { return mData+E; }
- constexpr reverse_iterator rbegin() const noexcept { return reverse_iterator{end()}; }
- constexpr reverse_iterator rend() const noexcept { return reverse_iterator{begin()}; }
- constexpr const_reverse_iterator crbegin() const noexcept
+ [[nodiscard]] constexpr auto rbegin() const noexcept -> reverse_iterator { return reverse_iterator{end()}; }
+ [[nodiscard]] constexpr auto rend() const noexcept -> reverse_iterator { return reverse_iterator{begin()}; }
+ [[nodiscard]] constexpr auto crbegin() const noexcept -> const_reverse_iterator
{ return const_reverse_iterator{cend()}; }
- constexpr const_reverse_iterator crend() const noexcept
+ [[nodiscard]] constexpr auto crend() const noexcept -> const_reverse_iterator
{ return const_reverse_iterator{cbegin()}; }
template<size_t C>
- constexpr span<element_type,C> first() const
+ [[nodiscard]] constexpr auto first() const -> span<element_type,C>
{
static_assert(E >= C, "New size exceeds original capacity");
return span<element_type,C>{mData, C};
}
template<size_t C>
- constexpr span<element_type,C> last() const
+ [[nodiscard]] constexpr auto last() const -> span<element_type,C>
{
static_assert(E >= C, "New size exceeds original capacity");
return span<element_type,C>{mData+(E-C), C};
}
template<size_t O, size_t C>
- constexpr auto subspan() const -> std::enable_if_t<C!=dynamic_extent,span<element_type,C>>
+ [[nodiscard]] constexpr auto subspan() const -> std::enable_if_t<C!=dynamic_extent,span<element_type,C>>
{
static_assert(E >= O, "Offset exceeds extent");
static_assert(E-O >= C, "New size exceeds original capacity");
@@ -151,7 +152,7 @@ public:
}
template<size_t O, size_t C=dynamic_extent>
- constexpr auto subspan() const -> std::enable_if_t<C==dynamic_extent,span<element_type,E-O>>
+ [[nodiscard]] constexpr auto subspan() const -> std::enable_if_t<C==dynamic_extent,span<element_type,E-O>>
{
static_assert(E >= O, "Offset exceeds extent");
return span<element_type,E-O>{mData+O, E-O};
@@ -161,10 +162,10 @@ public:
* defining the specialization. As a result, these methods need to be
* defined later.
*/
- constexpr span<element_type,dynamic_extent> first(size_t count) const;
- constexpr span<element_type,dynamic_extent> last(size_t count) const;
- constexpr span<element_type,dynamic_extent> subspan(size_t offset,
- size_t count=dynamic_extent) const;
+ [[nodiscard]] constexpr auto first(size_t count) const -> span<element_type,dynamic_extent>;
+ [[nodiscard]] constexpr auto last(size_t count) const -> span<element_type,dynamic_extent>;
+ [[nodiscard]] constexpr auto subspan(size_t offset,
+ size_t count=dynamic_extent) const -> span<element_type,dynamic_extent>;
private:
pointer mData{nullptr};
@@ -192,14 +193,14 @@ public:
constexpr span() noexcept = default;
template<typename U>
- constexpr span(U iter, index_type count) : mData{::al::to_address(iter)}, mDataEnd{::al::to_address(iter) + count}
+ constexpr span(U iter, index_type count) : mData{::al::to_address(iter)}, mDataLength{count}
{ }
template<typename U, typename V, REQUIRES(!std::is_convertible<V,size_t>::value)>
constexpr span(U first, V last) : span{::al::to_address(first), static_cast<size_t>(last - first)}
{ }
template<size_t N>
- constexpr span(type_identity_t<element_type> (&arr)[N]) noexcept
+ constexpr span(type_identity_t<element_type> (&arr)[N]) noexcept /* NOLINT(*-avoid-c-arrays) */
: span{std::data(arr), std::size(arr)}
{ }
template<size_t N>
@@ -221,83 +222,122 @@ public:
constexpr span& operator=(const span &rhs) noexcept = default;
- constexpr reference front() const { return *mData; }
- constexpr reference back() const { return *(mDataEnd-1); }
- constexpr reference operator[](index_type idx) const { return mData[idx]; }
- constexpr pointer data() const noexcept { return mData; }
+ [[nodiscard]] constexpr auto front() const -> reference { return mData[0]; }
+ [[nodiscard]] constexpr auto back() const -> reference { return mData[mDataLength-1]; }
+ [[nodiscard]] constexpr auto operator[](index_type idx) const -> reference { return mData[idx]; }
+ [[nodiscard]] constexpr auto data() const noexcept -> pointer { return mData; }
- constexpr index_type size() const noexcept { return static_cast<index_type>(mDataEnd-mData); }
- constexpr index_type size_bytes() const noexcept
- { return static_cast<index_type>(mDataEnd-mData) * sizeof(value_type); }
- constexpr bool empty() const noexcept { return mData == mDataEnd; }
+ [[nodiscard]] constexpr auto size() const noexcept -> index_type { return mDataLength; }
+ [[nodiscard]] constexpr auto size_bytes() const noexcept -> index_type { return mDataLength * sizeof(value_type); }
+ [[nodiscard]] constexpr auto empty() const noexcept -> bool { return mDataLength == 0; }
- constexpr iterator begin() const noexcept { return mData; }
- constexpr iterator end() const noexcept { return mDataEnd; }
- constexpr const_iterator cbegin() const noexcept { return mData; }
- constexpr const_iterator cend() const noexcept { return mDataEnd; }
+ [[nodiscard]] constexpr auto begin() const noexcept -> iterator { return mData; }
+ [[nodiscard]] constexpr auto end() const noexcept -> iterator { return mData+mDataLength; }
+ [[nodiscard]] constexpr auto cbegin() const noexcept -> const_iterator { return mData; }
+ [[nodiscard]] constexpr auto cend() const noexcept -> const_iterator { return mData+mDataLength; }
- constexpr reverse_iterator rbegin() const noexcept { return reverse_iterator{end()}; }
- constexpr reverse_iterator rend() const noexcept { return reverse_iterator{begin()}; }
- constexpr const_reverse_iterator crbegin() const noexcept
+ [[nodiscard]] constexpr auto rbegin() const noexcept -> reverse_iterator { return reverse_iterator{end()}; }
+ [[nodiscard]] constexpr auto rend() const noexcept -> reverse_iterator { return reverse_iterator{begin()}; }
+ [[nodiscard]] constexpr auto crbegin() const noexcept -> const_reverse_iterator
{ return const_reverse_iterator{cend()}; }
- constexpr const_reverse_iterator crend() const noexcept
+ [[nodiscard]] constexpr auto crend() const noexcept -> const_reverse_iterator
{ return const_reverse_iterator{cbegin()}; }
template<size_t C>
- constexpr span<element_type,C> first() const
- { return span<element_type,C>{mData, C}; }
+ [[nodiscard]] constexpr auto first() const -> span<element_type,C>
+ {
+ if(C > mDataLength)
+ throw std::out_of_range{"Subspan count out of range"};
+ return span<element_type,C>{mData, C};
+ }
- constexpr span first(size_t count) const
- { return (count >= size()) ? *this : span{mData, mData+count}; }
+ [[nodiscard]] constexpr auto first(size_t count) const -> span
+ {
+ if(count > mDataLength)
+ throw std::out_of_range{"Subspan count out of range"};
+ return span{mData, count};
+ }
template<size_t C>
- constexpr span<element_type,C> last() const
- { return span<element_type,C>{mDataEnd-C, C}; }
+ [[nodiscard]] constexpr auto last() const -> span<element_type,C>
+ {
+ if(C > mDataLength)
+ throw std::out_of_range{"Subspan count out of range"};
+ return span<element_type,C>{mData+mDataLength-C, C};
+ }
- constexpr span last(size_t count) const
- { return (count >= size()) ? *this : span{mDataEnd-count, mDataEnd}; }
+ [[nodiscard]] constexpr auto last(size_t count) const -> span
+ {
+ if(count > mDataLength)
+ throw std::out_of_range{"Subspan count out of range"};
+ return span{mData+mDataLength-count, count};
+ }
template<size_t O, size_t C>
- constexpr auto subspan() const -> std::enable_if_t<C!=dynamic_extent,span<element_type,C>>
- { return span<element_type,C>{mData+O, C}; }
+ [[nodiscard]] constexpr auto subspan() const -> std::enable_if_t<C!=dynamic_extent,span<element_type,C>>
+ {
+ if(O > mDataLength)
+ throw std::out_of_range{"Subspan offset out of range"};
+ if(C > mDataLength-O)
+ throw std::out_of_range{"Subspan length out of range"};
+ return span<element_type,C>{mData+O, C};
+ }
template<size_t O, size_t C=dynamic_extent>
- constexpr auto subspan() const -> std::enable_if_t<C==dynamic_extent,span<element_type,C>>
- { return span<element_type,C>{mData+O, mDataEnd}; }
+ [[nodiscard]] constexpr auto subspan() const -> std::enable_if_t<C==dynamic_extent,span<element_type,C>>
+ {
+ if(O > mDataLength)
+ throw std::out_of_range{"Subspan offset out of range"};
+ return span<element_type,C>{mData+O, mDataLength-O};
+ }
- constexpr span subspan(size_t offset, size_t count=dynamic_extent) const
+ [[nodiscard]] constexpr auto subspan(size_t offset, size_t count=dynamic_extent) const -> span
{
- return (offset > size()) ? span{} :
- (count >= size()-offset) ? span{mData+offset, mDataEnd} :
- span{mData+offset, mData+offset+count};
+ if(offset > mDataLength)
+ throw std::out_of_range{"Subspan offset out of range"};
+ if(count != dynamic_extent)
+ {
+ if(count > mDataLength-offset)
+ throw std::out_of_range{"Subspan length out of range"};
+ return span{mData+offset, count};
+ }
+ return span{mData+offset, mDataLength-offset};
}
private:
pointer mData{nullptr};
- pointer mDataEnd{nullptr};
+ index_type mDataLength{0};
};
template<typename T, size_t E>
-constexpr inline auto span<T,E>::first(size_t count) const -> span<element_type,dynamic_extent>
+[[nodiscard]] constexpr inline auto span<T,E>::first(size_t count) const -> span<element_type,dynamic_extent>
{
- return (count >= size()) ? span<element_type>{mData, extent} :
- span<element_type>{mData, count};
+ if(count > size())
+ throw std::out_of_range{"Subspan count out of range"};
+ return span<element_type>{mData, count};
}
template<typename T, size_t E>
-constexpr inline auto span<T,E>::last(size_t count) const -> span<element_type,dynamic_extent>
+[[nodiscard]] constexpr inline auto span<T,E>::last(size_t count) const -> span<element_type,dynamic_extent>
{
- return (count >= size()) ? span<element_type>{mData, extent} :
- span<element_type>{mData+extent-count, count};
+ if(count > size())
+ throw std::out_of_range{"Subspan count out of range"};
+ return span<element_type>{mData+size()-count, count};
}
template<typename T, size_t E>
-constexpr inline auto span<T,E>::subspan(size_t offset, size_t count) const
+[[nodiscard]] constexpr inline auto span<T,E>::subspan(size_t offset, size_t count) const
-> span<element_type,dynamic_extent>
{
- return (offset > size()) ? span<element_type>{} :
- (count >= size()-offset) ? span<element_type>{mData+offset, mData+extent} :
- span<element_type>{mData+offset, mData+offset+count};
+ if(offset > size())
+ throw std::out_of_range{"Subspan offset out of range"};
+ if(count != dynamic_extent)
+ {
+ if(count > size()-offset)
+ throw std::out_of_range{"Subspan length out of range"};
+ return span{mData+offset, count};
+ }
+ return span{mData+offset, size()-offset};
}
@@ -305,7 +345,7 @@ template<typename T, typename EndOrSize>
span(T, EndOrSize) -> span<std::remove_reference_t<decltype(*std::declval<T&>())>>;
template<typename T, std::size_t N>
-span(T (&)[N]) -> span<T, N>;
+span(T (&)[N]) -> span<T, N>; /* NOLINT(*-avoid-c-arrays) */
template<typename T, std::size_t N>
span(std::array<T, N>&) -> span<T, N>;
diff --git a/common/althrd_setname.cpp b/common/althrd_setname.cpp
index 22d33092..21197ba0 100644
--- a/common/althrd_setname.cpp
+++ b/common/althrd_setname.cpp
@@ -60,7 +60,7 @@ using setname_t4 = int(*)(pthread_t, const char*, void*);
{ func(pthread_self(), name); }
[[maybe_unused]] void setname_caller(setname_t4 func, const char *name)
-{ func(pthread_self(), "%s", static_cast<void*>(const_cast<char*>(name))); }
+{ func(pthread_self(), "%s", const_cast<char*>(name)); /* NOLINT(*-const-cast) */ }
} // namespace
diff --git a/common/atomic.h b/common/atomic.h
index 5e9b04c6..e85c4f76 100644
--- a/common/atomic.h
+++ b/common/atomic.h
@@ -2,17 +2,16 @@
#define AL_ATOMIC_H
#include <atomic>
+#include <memory>
+#include "almalloc.h"
-using RefCount = std::atomic<unsigned int>;
-
-inline void InitRef(RefCount &ref, unsigned int value)
-{ ref.store(value, std::memory_order_relaxed); }
-inline unsigned int ReadRef(RefCount &ref)
-{ return ref.load(std::memory_order_acquire); }
-inline unsigned int IncrementRef(RefCount &ref)
+template<typename T>
+auto IncrementRef(std::atomic<T> &ref) noexcept
{ return ref.fetch_add(1u, std::memory_order_acq_rel)+1u; }
-inline unsigned int DecrementRef(RefCount &ref)
+
+template<typename T>
+auto DecrementRef(std::atomic<T> &ref) noexcept
{ return ref.fetch_sub(1u, std::memory_order_acq_rel)-1u; }
@@ -30,4 +29,75 @@ inline void AtomicReplaceHead(std::atomic<T> &head, T newhead)
std::memory_order_acq_rel, std::memory_order_acquire));
}
+namespace al {
+
+template<typename T, typename D=std::default_delete<T>>
+class atomic_unique_ptr {
+ std::atomic<gsl::owner<T*>> mPointer{};
+
+ using unique_ptr_t = std::unique_ptr<T,D>;
+
+public:
+ atomic_unique_ptr() = default;
+ atomic_unique_ptr(const atomic_unique_ptr&) = delete;
+ explicit atomic_unique_ptr(std::nullptr_t) noexcept { }
+ explicit atomic_unique_ptr(gsl::owner<T*> ptr) noexcept : mPointer{ptr} { }
+ explicit atomic_unique_ptr(unique_ptr_t&& rhs) noexcept : mPointer{rhs.release()} { }
+ ~atomic_unique_ptr()
+ {
+ if(auto ptr = mPointer.exchange(nullptr, std::memory_order_relaxed))
+ D{}(ptr);
+ }
+
+ auto operator=(const atomic_unique_ptr&) -> atomic_unique_ptr& = delete;
+ auto operator=(std::nullptr_t) noexcept -> atomic_unique_ptr&
+ {
+ if(auto ptr = mPointer.exchange(nullptr))
+ D{}(ptr);
+ return *this;
+ }
+ auto operator=(unique_ptr_t&& rhs) noexcept -> atomic_unique_ptr&
+ {
+ if(auto ptr = mPointer.exchange(rhs.release()))
+ D{}(ptr);
+ return *this;
+ }
+
+ [[nodiscard]]
+ auto load(std::memory_order m=std::memory_order_seq_cst) const noexcept -> T*
+ { return mPointer.load(m); }
+ void store(std::nullptr_t, std::memory_order m=std::memory_order_seq_cst) noexcept
+ {
+ if(auto oldptr = mPointer.exchange(nullptr, m))
+ D{}(oldptr);
+ }
+ void store(gsl::owner<T*> ptr, std::memory_order m=std::memory_order_seq_cst) noexcept
+ {
+ if(auto oldptr = mPointer.exchange(ptr, m))
+ D{}(oldptr);
+ }
+ void store(unique_ptr_t&& ptr, std::memory_order m=std::memory_order_seq_cst) noexcept
+ {
+ if(auto oldptr = mPointer.exchange(ptr.release(), m))
+ D{}(oldptr);
+ }
+
+ [[nodiscard]]
+ auto exchange(std::nullptr_t, std::memory_order m=std::memory_order_seq_cst) noexcept -> unique_ptr_t
+ { return unique_ptr_t{mPointer.exchange(nullptr, m)}; }
+ [[nodiscard]]
+ auto exchange(gsl::owner<T*> ptr, std::memory_order m=std::memory_order_seq_cst) noexcept -> unique_ptr_t
+ { return unique_ptr_t{mPointer.exchange(ptr, m)}; }
+ [[nodiscard]]
+ auto exchange(std::unique_ptr<T>&& ptr, std::memory_order m=std::memory_order_seq_cst) noexcept -> unique_ptr_t
+ { return unique_ptr_t{mPointer.exchange(ptr.release(), m)}; }
+
+ [[nodiscard]]
+ auto is_lock_free() const noexcept -> bool { return mPointer.is_lock_free(); }
+
+ static constexpr auto is_always_lock_free = std::atomic<gsl::owner<T*>>::is_always_lock_free;
+};
+
+} // namespace al
+
#endif /* AL_ATOMIC_H */
diff --git a/common/dynload.cpp b/common/dynload.cpp
index 86c36e00..333a9435 100644
--- a/common/dynload.cpp
+++ b/common/dynload.cpp
@@ -3,13 +3,12 @@
#include "dynload.h"
-#include "albit.h"
-#include "strutils.h"
-
#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
+#include "strutils.h"
+
void *LoadLib(const char *name)
{
std::wstring wname{utf8_to_wstr(name)};
@@ -18,7 +17,7 @@ void *LoadLib(const char *name)
void CloseLib(void *handle)
{ FreeLibrary(static_cast<HMODULE>(handle)); }
void *GetSymbol(void *handle, const char *name)
-{ return al::bit_cast<void*>(GetProcAddress(static_cast<HMODULE>(handle), name)); }
+{ return reinterpret_cast<void*>(GetProcAddress(static_cast<HMODULE>(handle), name)); }
#elif defined(HAVE_DLFCN_H)
diff --git a/common/flexarray.h b/common/flexarray.h
new file mode 100644
index 00000000..b8077988
--- /dev/null
+++ b/common/flexarray.h
@@ -0,0 +1,125 @@
+#ifndef AL_FLEXARRAY_H
+#define AL_FLEXARRAY_H
+
+#include <algorithm>
+#include <cstddef>
+#include <stdexcept>
+#include <type_traits>
+
+#include "almalloc.h"
+#include "alspan.h"
+
+namespace al {
+
+/* Storage for flexible array data. This is trivially destructible if type T is
+ * trivially destructible.
+ */
+template<typename T, size_t alignment, bool = std::is_trivially_destructible<T>::value>
+struct alignas(std::max(alignment, alignof(al::span<T>))) FlexArrayStorage : al::span<T> {
+ static constexpr size_t Sizeof(size_t count, size_t base=0u) noexcept
+ { return sizeof(FlexArrayStorage) + sizeof(T)*count + base; }
+
+ FlexArrayStorage(size_t size) noexcept(std::is_nothrow_constructible_v<T>)
+ : al::span<T>{::new(static_cast<void*>(this+1)) T[size], size}
+ { }
+ ~FlexArrayStorage() = default;
+
+ FlexArrayStorage(const FlexArrayStorage&) = delete;
+ FlexArrayStorage& operator=(const FlexArrayStorage&) = delete;
+};
+
+template<typename T, size_t alignment>
+struct alignas(std::max(alignment, alignof(al::span<T>))) FlexArrayStorage<T,alignment,false> : al::span<T> {
+ static constexpr size_t Sizeof(size_t count, size_t base=0u) noexcept
+ { return sizeof(FlexArrayStorage) + sizeof(T)*count + base; }
+
+ FlexArrayStorage(size_t size) noexcept(std::is_nothrow_constructible_v<T>)
+ : al::span<T>{::new(static_cast<void*>(this+1)) T[size], size}
+ { }
+ ~FlexArrayStorage() { std::destroy(this->begin(), this->end()); }
+
+ FlexArrayStorage(const FlexArrayStorage&) = delete;
+ FlexArrayStorage& operator=(const FlexArrayStorage&) = delete;
+};
+
+/* A flexible array type. Used either standalone or at the end of a parent
+ * struct, to have a run-time-sized array that's embedded with its size. Should
+ * be used delicately, ensuring there's no additional data after the FlexArray
+ * member.
+ */
+template<typename T, size_t Align=alignof(T)>
+struct FlexArray {
+ using element_type = T;
+ using value_type = std::remove_cv_t<T>;
+ using index_type = size_t;
+ using difference_type = ptrdiff_t;
+
+ using pointer = T*;
+ using const_pointer = const T*;
+ using reference = T&;
+ using const_reference = const T&;
+
+ using iterator = pointer;
+ using const_iterator = const_pointer;
+ using reverse_iterator = std::reverse_iterator<iterator>;
+ using const_reverse_iterator = std::reverse_iterator<const_iterator>;
+
+ static constexpr size_t alignment{std::max(alignof(T), Align)};
+ using Storage_t_ = FlexArrayStorage<element_type,alignment>;
+
+ const Storage_t_ mStore;
+
+ static constexpr index_type Sizeof(index_type count, index_type base=0u) noexcept
+ { return Storage_t_::Sizeof(count, base); }
+ static std::unique_ptr<FlexArray> Create(index_type count)
+ { return std::unique_ptr<FlexArray>{new(FamCount{count}) FlexArray{count}}; }
+
+ FlexArray(index_type size) noexcept(std::is_nothrow_constructible_v<Storage_t_,index_type>)
+ : mStore{size}
+ { }
+ ~FlexArray() = default;
+
+ [[nodiscard]] auto size() const noexcept -> index_type { return mStore.size(); }
+ [[nodiscard]] auto empty() const noexcept -> bool { return mStore.empty(); }
+
+ [[nodiscard]] auto data() noexcept -> pointer { return mStore.data(); }
+ [[nodiscard]] auto data() const noexcept -> const_pointer { return mStore.data(); }
+
+ [[nodiscard]] auto operator[](index_type i) noexcept -> reference { return mStore[i]; }
+ [[nodiscard]] auto operator[](index_type i) const noexcept -> const_reference { return mStore[i]; }
+
+ [[nodiscard]] auto front() noexcept -> reference { return mStore.front(); }
+ [[nodiscard]] auto front() const noexcept -> const_reference { return mStore.front(); }
+
+ [[nodiscard]] auto back() noexcept -> reference { return mStore.back(); }
+ [[nodiscard]] auto back() const noexcept -> const_reference { return mStore.back(); }
+
+ [[nodiscard]] auto begin() noexcept -> iterator { return mStore.begin(); }
+ [[nodiscard]] auto begin() const noexcept -> const_iterator { return mStore.cbegin(); }
+ [[nodiscard]] auto cbegin() const noexcept -> const_iterator { return mStore.cbegin(); }
+ [[nodiscard]] auto end() noexcept -> iterator { return mStore.end(); }
+ [[nodiscard]] auto end() const noexcept -> const_iterator { return mStore.cend(); }
+ [[nodiscard]] auto cend() const noexcept -> const_iterator { return mStore.cend(); }
+
+ [[nodiscard]] auto rbegin() noexcept -> reverse_iterator { return end(); }
+ [[nodiscard]] auto rbegin() const noexcept -> const_reverse_iterator { return cend(); }
+ [[nodiscard]] auto crbegin() const noexcept -> const_reverse_iterator { return cend(); }
+ [[nodiscard]] auto rend() noexcept -> reverse_iterator { return begin(); }
+ [[nodiscard]] auto rend() const noexcept -> const_reverse_iterator { return cbegin(); }
+ [[nodiscard]] auto crend() const noexcept -> const_reverse_iterator { return cbegin(); }
+
+ gsl::owner<void*> operator new(size_t, FamCount count)
+ { return ::operator new[](Sizeof(count), std::align_val_t{alignof(FlexArray)}); }
+ void operator delete(gsl::owner<void*> block, FamCount) noexcept
+ { ::operator delete[](block, std::align_val_t{alignof(FlexArray)}); }
+ void operator delete(gsl::owner<void*> block) noexcept
+ { ::operator delete[](block, std::align_val_t{alignof(FlexArray)}); }
+
+ void *operator new(size_t size) = delete;
+ void *operator new[](size_t size) = delete;
+ void operator delete[](void *block) = delete;
+};
+
+} // namespace al
+
+#endif /* AL_FLEXARRAY_H */
diff --git a/common/intrusive_ptr.h b/common/intrusive_ptr.h
index 27075347..0152b92a 100644
--- a/common/intrusive_ptr.h
+++ b/common/intrusive_ptr.h
@@ -11,7 +11,7 @@ namespace al {
template<typename T>
class intrusive_ref {
- RefCount mRef{1u};
+ std::atomic<unsigned int> mRef{1u};
public:
unsigned int add_ref() noexcept { return IncrementRef(mRef); }
@@ -81,9 +81,9 @@ public:
explicit operator bool() const noexcept { return mPtr != nullptr; }
- T& operator*() const noexcept { return *mPtr; }
- T* operator->() const noexcept { return mPtr; }
- T* get() const noexcept { return mPtr; }
+ [[nodiscard]] auto operator*() const noexcept -> T& { return *mPtr; }
+ [[nodiscard]] auto operator->() const noexcept -> T* { return mPtr; }
+ [[nodiscard]] auto get() const noexcept -> T* { return mPtr; }
void reset(T *ptr=nullptr) noexcept
{
diff --git a/common/opthelpers.h b/common/opthelpers.h
index dc43ccdb..ae2611da 100644
--- a/common/opthelpers.h
+++ b/common/opthelpers.h
@@ -42,7 +42,7 @@
#elif HAS_BUILTIN(__builtin_unreachable)
#define ASSUME(x) do { if(x) break; __builtin_unreachable(); } while(0)
#else
-#define ASSUME(x) ((void)0)
+#define ASSUME(x) (static_cast<void>(0))
#endif
/* This shouldn't be needed since unknown attributes are ignored, but older
diff --git a/common/pffft.cpp b/common/pffft.cpp
index 71f71fa6..46d97918 100644
--- a/common/pffft.cpp
+++ b/common/pffft.cpp
@@ -58,16 +58,17 @@
#include "pffft.h"
#include <array>
-#include <assert.h>
+#include <cassert>
#include <cmath>
+#include <cstdio>
+#include <cstdlib>
#include <cstring>
-#include <stdio.h>
-#include <stdlib.h>
#include <vector>
#include "albit.h"
#include "almalloc.h"
#include "alnumbers.h"
+#include "alnumeric.h"
#include "alspan.h"
#include "opthelpers.h"
@@ -90,8 +91,8 @@ using uint = unsigned int;
* Altivec support macros
*/
#if defined(__ppc__) || defined(__ppc64__) || defined(__powerpc__) || defined(__powerpc64__)
-typedef vector float v4sf;
-#define SIMD_SZ 4
+using v4sf = vector float;
+constexpr uint SimdSize{4};
#define VZERO() ((vector float) vec_splat_u8(0))
#define VMUL(a,b) vec_madd(a,b, VZERO())
#define VADD vec_add
@@ -142,19 +143,27 @@ force_inline void vtranspose4(v4sf &x0, v4sf &x1, v4sf &x2, v4sf &x3) noexcept
(defined(_M_IX86_FP) && _M_IX86_FP >= 1)
#include <xmmintrin.h>
-typedef __m128 v4sf;
-#define SIMD_SZ 4 // 4 floats by simd vector -- this is pretty much hardcoded in the preprocess/finalize functions anyway so you will have to work if you want to enable AVX with its 256-bit vectors.
+using v4sf = __m128;
+/* 4 floats by simd vector -- this is pretty much hardcoded in the preprocess/
+ * finalize functions anyway so you will have to work if you want to enable AVX
+ * with its 256-bit vectors.
+ */
+constexpr uint SimdSize{4};
#define VZERO _mm_setzero_ps
#define VMUL _mm_mul_ps
#define VADD _mm_add_ps
-#define VMADD(a,b,c) _mm_add_ps(_mm_mul_ps(a,b), c)
+force_inline v4sf vmadd(const v4sf a, const v4sf b, const v4sf c) noexcept
+{ return _mm_add_ps(_mm_mul_ps(a,b), c); }
+#define VMADD vmadd
#define VSUB _mm_sub_ps
#define LD_PS1 _mm_set1_ps
#define VSET4 _mm_setr_ps
-#define VINSERT0(v, a) _mm_move_ss((v), _mm_set_ss(a))
+force_inline v4sf vinsert0(const v4sf v, const float a) noexcept
+{ return _mm_move_ss(v, _mm_set_ss(a)); }
+#define VINSERT0 vinsert0
#define VEXTRACT0 _mm_cvtss_f32
-force_inline void interleave2(v4sf in1, v4sf in2, v4sf &out1, v4sf &out2) noexcept
+force_inline void interleave2(const v4sf in1, const v4sf in2, v4sf &out1, v4sf &out2) noexcept
{
v4sf tmp{_mm_unpacklo_ps(in1, in2)};
out2 = _mm_unpackhi_ps(in1, in2);
@@ -170,7 +179,7 @@ force_inline void uninterleave2(v4sf in1, v4sf in2, v4sf &out1, v4sf &out2) noex
force_inline void vtranspose4(v4sf &x0, v4sf &x1, v4sf &x2, v4sf &x3) noexcept
{ _MM_TRANSPOSE4_PS(x0, x1, x2, x3); }
-#define VSWAPHL(a,b) _mm_shuffle_ps(b, a, _MM_SHUFFLE(3,2,1,0))
+#define VSWAPHL(a,b) _mm_shuffle_ps((b), (a), _MM_SHUFFLE(3,2,1,0))
/*
* ARM NEON support macros
@@ -178,8 +187,8 @@ force_inline void vtranspose4(v4sf &x0, v4sf &x1, v4sf &x2, v4sf &x3) noexcept
#elif defined(__ARM_NEON) || defined(__aarch64__) || defined(__arm64)
#include <arm_neon.h>
-typedef float32x4_t v4sf;
-#define SIMD_SZ 4
+using v4sf = float32x4_t;
+constexpr uint SimdSize{4};
#define VZERO() vdupq_n_f32(0)
#define VMUL vmulq_f32
#define VADD vaddq_f32
@@ -238,7 +247,7 @@ force_inline void vtranspose4(v4sf &x0, v4sf &x1, v4sf &x2, v4sf &x3) noexcept
#elif defined(__GNUC__)
using v4sf [[gnu::vector_size(16), gnu::aligned(16)]] = float;
-#define SIMD_SZ 4
+constexpr uint SimdSize{4};
#define VZERO() v4sf{0,0,0,0}
#define VMUL(a,b) ((a) * (b))
#define VADD(a,b) ((a) + (b))
@@ -297,8 +306,8 @@ force_inline v4sf vswaphl(v4sf a, v4sf b) noexcept
// fallback mode for situations where SIMD is not available, use scalar mode instead
#ifdef PFFFT_SIMD_DISABLE
-typedef float v4sf;
-#define SIMD_SZ 1
+using v4sf = float;
+constexpr uint SimdSize{1};
#define VZERO() 0.f
#define VMUL(a,b) ((a)*(b))
#define VADD(a,b) ((a)+(b))
@@ -309,7 +318,7 @@ typedef float v4sf;
inline bool valigned(const float *ptr) noexcept
{
- static constexpr uintptr_t alignmask{SIMD_SZ*4 - 1};
+ static constexpr uintptr_t alignmask{SimdSize*4 - 1};
return (reinterpret_cast<uintptr_t>(ptr) & alignmask) == 0;
}
@@ -335,14 +344,14 @@ force_inline void vcplxmulconj(v4sf &ar, v4sf &ai, v4sf br, v4sf bi) noexcept
[[maybe_unused]] void validate_pffft_simd()
{
using float4 = std::array<float,4>;
- static constexpr float f[16]{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
+ static constexpr std::array<float,16> f{{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}};
float4 a0_f, a1_f, a2_f, a3_f, t_f, u_f;
v4sf a0_v, a1_v, a2_v, a3_v, t_v, u_v;
- std::memcpy(&a0_v, f, 4*sizeof(float));
- std::memcpy(&a1_v, f+4, 4*sizeof(float));
- std::memcpy(&a2_v, f+8, 4*sizeof(float));
- std::memcpy(&a3_v, f+12, 4*sizeof(float));
+ std::memcpy(&a0_v, f.data(), 4*sizeof(float));
+ std::memcpy(&a1_v, f.data()+4, 4*sizeof(float));
+ std::memcpy(&a2_v, f.data()+8, 4*sizeof(float));
+ std::memcpy(&a3_v, f.data()+12, 4*sizeof(float));
t_v = VZERO(); t_f = al::bit_cast<float4>(t_v);
printf("VZERO=[%2g %2g %2g %2g]\n", t_f[0], t_f[1], t_f[2], t_f[3]); assertv4(t, 0, 0, 0, 0);
@@ -379,7 +388,9 @@ force_inline void vcplxmulconj(v4sf &ar, v4sf &ai, v4sf br, v4sf bi) noexcept
#endif //!PFFFT_SIMD_DISABLE
/* SSE and co like 16-bytes aligned pointers */
-#define MALLOC_V4SF_ALIGNMENT 64 // with a 64-byte alignment, we are even aligned on L2 cache lines...
+/* with a 64-byte alignment, we are even aligned on L2 cache lines... */
+constexpr auto V4sfAlignment = size_t(64);
+constexpr auto V4sfAlignVal = std::align_val_t(V4sfAlignment);
/*
passf2 and passb2 has been merged here, fsign = -1 for passf2, +1 for passb2
@@ -538,8 +549,8 @@ NOINLINE void passf5_ps(const size_t ido, const size_t l1, const v4sf *cc, v4sf
const v4sf ti11{LD_PS1(0.951056516295154f*fsign)};
const v4sf ti12{LD_PS1(0.587785252292473f*fsign)};
-#define cc_ref(a_1,a_2) cc[(a_2-1)*ido + (a_1) + 1]
-#define ch_ref(a_1,a_3) ch[(a_3-1)*l1*ido + (a_1) + 1]
+#define cc_ref(a_1,a_2) cc[((a_2)-1)*ido + (a_1) + 1]
+#define ch_ref(a_1,a_3) ch[((a_3)-1)*l1*ido + (a_1) + 1]
assert(ido > 2);
for(size_t k{0};k < l1;++k, cc += 5*ido, ch += ido)
@@ -958,8 +969,8 @@ void radf5_ps(const size_t ido, const size_t l1, const v4sf *RESTRICT cc, v4sf *
const v4sf tr12{LD_PS1(-0.809016994374947f)};
const v4sf ti12{LD_PS1(0.587785252292473f)};
-#define cc_ref(a_1,a_2,a_3) cc[((a_3)*l1 + (a_2))*ido + a_1]
-#define ch_ref(a_1,a_2,a_3) ch[((a_3)*5 + (a_2))*ido + a_1]
+#define cc_ref(a_1,a_2,a_3) cc[((a_3)*l1 + (a_2))*ido + (a_1)]
+#define ch_ref(a_1,a_2,a_3) ch[((a_3)*5 + (a_2))*ido + (a_1)]
/* Parameter adjustments */
ch -= 1 + ido * 6;
@@ -1040,8 +1051,8 @@ void radb5_ps(const size_t ido, const size_t l1, const v4sf *RESTRICT cc, v4sf *
const v4sf tr12{LD_PS1(-0.809016994374947f)};
const v4sf ti12{LD_PS1(0.587785252292473f)};
-#define cc_ref(a_1,a_2,a_3) cc[((a_3)*5 + (a_2))*ido + a_1]
-#define ch_ref(a_1,a_2,a_3) ch[((a_3)*l1 + (a_2))*ido + a_1]
+#define cc_ref(a_1,a_2,a_3) cc[((a_3)*5 + (a_2))*ido + (a_1)]
+#define ch_ref(a_1,a_2,a_3) ch[((a_3)*l1 + (a_2))*ido + (a_1)]
/* Parameter adjustments */
ch -= 1 + ido*(1 + l1);
@@ -1331,7 +1342,7 @@ uint decompose(const uint n, const al::span<uint,15> ifac, const al::span<const
void rffti1_ps(const uint n, float *wa, const al::span<uint,15> ifac)
{
- static constexpr uint ntryh[]{4,2,3,5};
+ static constexpr std::array ntryh{4u,2u,3u,5u};
const uint nf{decompose(n, ifac, ntryh)};
const double argh{2.0*al::numbers::pi / n};
@@ -1365,7 +1376,7 @@ void rffti1_ps(const uint n, float *wa, const al::span<uint,15> ifac)
void cffti1_ps(const uint n, float *wa, const al::span<uint,15> ifac)
{
- static constexpr uint ntryh[]{5,3,4,2};
+ static constexpr std::array ntryh{5u,3u,4u,2u};
const uint nf{decompose(n, ifac, ntryh)};
const double argh{2.0*al::numbers::pi / n};
@@ -1405,24 +1416,20 @@ void cffti1_ps(const uint n, float *wa, const al::span<uint,15> ifac)
} // namespace
-void *pffft_aligned_malloc(size_t nb_bytes)
-{ return al_malloc(MALLOC_V4SF_ALIGNMENT, nb_bytes); }
-
-void pffft_aligned_free(void *p) { al_free(p); }
-
-int pffft_simd_size() { return SIMD_SZ; }
-
+/* NOLINTNEXTLINE(clang-analyzer-optin.performance.Padding) */
struct PFFFT_Setup {
- uint N;
- uint Ncvec; // nb of complex simd vectors (N/4 if PFFFT_COMPLEX, N/8 if PFFFT_REAL)
- std::array<uint,15> ifac;
- pffft_transform_t transform;
+ uint N{};
+ uint Ncvec{}; /* nb of complex simd vectors (N/4 if PFFFT_COMPLEX, N/8 if PFFFT_REAL) */
+ std::array<uint,15> ifac{};
+ pffft_transform_t transform{};
- float *twiddle; // N/4 elements
- alignas(MALLOC_V4SF_ALIGNMENT) v4sf e[1]; // N/4*3 elements
+ float *twiddle{}; /* N/4 elements */
+ al::span<v4sf> e; /* N/4*3 elements */
+
+ alignas(V4sfAlignment) std::byte end;
};
-PFFFT_Setup *pffft_new_setup(unsigned int N, pffft_transform_t transform)
+gsl::owner<PFFFT_Setup*> pffft_new_setup(unsigned int N, pffft_transform_t transform)
{
assert(transform == PFFFT_REAL || transform == PFFFT_COMPLEX);
assert(N > 0);
@@ -1431,50 +1438,53 @@ PFFFT_Setup *pffft_new_setup(unsigned int N, pffft_transform_t transform)
* handle other cases (or maybe just switch to a scalar fft, I don't know..)
*/
if(transform == PFFFT_REAL)
- assert((N%(2*SIMD_SZ*SIMD_SZ)) == 0);
+ assert((N%(2*SimdSize*SimdSize)) == 0);
else
- assert((N%(SIMD_SZ*SIMD_SZ)) == 0);
+ assert((N%(SimdSize*SimdSize)) == 0);
- const uint Ncvec = (transform == PFFFT_REAL ? N/2 : N)/SIMD_SZ;
- const size_t storelen{offsetof(PFFFT_Setup, e[0]) + (2u*Ncvec * sizeof(v4sf))};
+ const uint Ncvec{(transform == PFFFT_REAL ? N/2 : N) / SimdSize};
- void *store{al_calloc(MALLOC_V4SF_ALIGNMENT, storelen)};
- if(!store) return nullptr;
+ const size_t storelen{std::max(offsetof(PFFFT_Setup, end) + 2_zu*Ncvec*sizeof(v4sf),
+ sizeof(PFFFT_Setup))};
+ auto storage = static_cast<gsl::owner<std::byte*>>(::operator new[](storelen, V4sfAlignVal));
+ al::span extrastore{&storage[offsetof(PFFFT_Setup, end)], 2_zu*Ncvec*sizeof(v4sf)};
- PFFFT_Setup *s{::new(store) PFFFT_Setup{}};
+ gsl::owner<PFFFT_Setup*> s{::new(storage) PFFFT_Setup{}};
s->N = N;
s->transform = transform;
- /* nb of complex simd vectors */
s->Ncvec = Ncvec;
- s->twiddle = reinterpret_cast<float*>(&s->e[2u*Ncvec*(SIMD_SZ-1)/SIMD_SZ]);
- if constexpr(SIMD_SZ > 1)
+ const size_t ecount{2_zu*Ncvec*(SimdSize-1)/SimdSize};
+ s->e = {std::launder(reinterpret_cast<v4sf*>(extrastore.data())), ecount};
+ s->twiddle = std::launder(reinterpret_cast<float*>(&extrastore[ecount*sizeof(v4sf)]));
+
+ if constexpr(SimdSize > 1)
{
- auto e = std::vector<float>(2u*Ncvec*(SIMD_SZ-1), 0.0f);
+ auto e = std::vector<float>(s->e.size()*SimdSize, 0.0f);
for(size_t k{0};k < s->Ncvec;++k)
{
- const size_t i{k / SIMD_SZ};
- const size_t j{k % SIMD_SZ};
- for(size_t m{0};m < SIMD_SZ-1;++m)
+ const size_t i{k / SimdSize};
+ const size_t j{k % SimdSize};
+ for(size_t m{0};m < SimdSize-1;++m)
{
const double A{-2.0*al::numbers::pi*static_cast<double>((m+1)*k) / N};
- e[((i*3 + m)*2 + 0)*SIMD_SZ + j] = static_cast<float>(std::cos(A));
- e[((i*3 + m)*2 + 1)*SIMD_SZ + j] = static_cast<float>(std::sin(A));
+ e[((i*3 + m)*2 + 0)*SimdSize + j] = static_cast<float>(std::cos(A));
+ e[((i*3 + m)*2 + 1)*SimdSize + j] = static_cast<float>(std::sin(A));
}
}
- std::memcpy(s->e, e.data(), e.size()*sizeof(float));
+ std::memcpy(s->e.data(), e.data(), e.size()*sizeof(float));
}
if(transform == PFFFT_REAL)
- rffti1_ps(N/SIMD_SZ, s->twiddle, s->ifac);
+ rffti1_ps(N/SimdSize, s->twiddle, s->ifac);
else
- cffti1_ps(N/SIMD_SZ, s->twiddle, s->ifac);
+ cffti1_ps(N/SimdSize, s->twiddle, s->ifac);
/* check that N is decomposable with allowed prime factors */
size_t m{1};
for(size_t k{0};k < s->ifac[1];++k)
m *= s->ifac[2+k];
- if(m != N/SIMD_SZ)
+ if(m != N/SimdSize)
{
pffft_destroy_setup(s);
s = nullptr;
@@ -1484,10 +1494,10 @@ PFFFT_Setup *pffft_new_setup(unsigned int N, pffft_transform_t transform)
}
-void pffft_destroy_setup(PFFFT_Setup *s)
+void pffft_destroy_setup(gsl::owner<PFFFT_Setup*> s) noexcept
{
std::destroy_at(s);
- al_free(s);
+ ::operator delete[](gsl::owner<void*>{s}, V4sfAlignVal);
}
#if !defined(PFFFT_SIMD_DISABLE)
@@ -1537,7 +1547,7 @@ void pffft_cplx_finalize(const size_t Ncvec, const v4sf *in, v4sf *RESTRICT out,
{
assert(in != out);
- const size_t dk{Ncvec/SIMD_SZ}; // number of 4x4 matrix blocks
+ const size_t dk{Ncvec/SimdSize}; // number of 4x4 matrix blocks
for(size_t k{0};k < dk;++k)
{
v4sf r0{in[8*k+0]}, i0{in[8*k+1]};
@@ -1581,7 +1591,7 @@ void pffft_cplx_preprocess(const size_t Ncvec, const v4sf *in, v4sf *RESTRICT ou
{
assert(in != out);
- const size_t dk{Ncvec/SIMD_SZ}; // number of 4x4 matrix blocks
+ const size_t dk{Ncvec/SimdSize}; // number of 4x4 matrix blocks
for(size_t k{0};k < dk;++k)
{
v4sf r0{in[8*k+0]}, i0{in[8*k+1]};
@@ -1674,12 +1684,12 @@ NOINLINE void pffft_real_finalize(const size_t Ncvec, const v4sf *in, v4sf *REST
static constexpr float s{al::numbers::sqrt2_v<float>/2.0f};
assert(in != out);
- const size_t dk{Ncvec/SIMD_SZ}; // number of 4x4 matrix blocks
+ const size_t dk{Ncvec/SimdSize}; // number of 4x4 matrix blocks
/* fftpack order is f0r f1r f1i f2r f2i ... f(n-1)r f(n-1)i f(n)r */
const v4sf zero{VZERO()};
- const auto cr = al::bit_cast<std::array<float,SIMD_SZ>>(in[0]);
- const auto ci = al::bit_cast<std::array<float,SIMD_SZ>>(in[Ncvec*2-1]);
+ const auto cr = al::bit_cast<std::array<float,SimdSize>>(in[0]);
+ const auto ci = al::bit_cast<std::array<float,SimdSize>>(in[Ncvec*2-1]);
pffft_real_finalize_4x4(&zero, &zero, in+1, e, out);
/* [cr0 cr1 cr2 cr3 ci0 ci1 ci2 ci3]
@@ -1765,11 +1775,11 @@ NOINLINE void pffft_real_preprocess(const size_t Ncvec, const v4sf *in, v4sf *RE
static constexpr float sqrt2{al::numbers::sqrt2_v<float>};
assert(in != out);
- const size_t dk{Ncvec/SIMD_SZ}; // number of 4x4 matrix blocks
+ const size_t dk{Ncvec/SimdSize}; // number of 4x4 matrix blocks
/* fftpack order is f0r f1r f1i f2r f2i ... f(n-1)r f(n-1)i f(n)r */
- std::array<float,SIMD_SZ> Xr, Xi;
- for(size_t k{0};k < SIMD_SZ;++k)
+ std::array<float,SimdSize> Xr, Xi;
+ for(size_t k{0};k < SimdSize;++k)
{
Xr[k] = VEXTRACT0(in[2*k]);
Xi[k] = VEXTRACT0(in[2*k + 1]);
@@ -1813,7 +1823,7 @@ void pffft_transform_internal(const PFFFT_Setup *setup, const v4sf *vinput, v4sf
const size_t Ncvec{setup->Ncvec};
const bool nf_odd{(setup->ifac[1]&1) != 0};
- v4sf *buff[2]{voutput, scratch};
+ std::array buff{voutput, scratch};
bool ib{nf_odd != ordered};
if(direction == PFFFT_FORWARD)
{
@@ -1824,7 +1834,7 @@ void pffft_transform_internal(const PFFFT_Setup *setup, const v4sf *vinput, v4sf
if(setup->transform == PFFFT_REAL)
{
ib = (rfftf1_ps(Ncvec*2, vinput, buff[ib], buff[!ib], setup->twiddle, setup->ifac) == buff[1]);
- pffft_real_finalize(Ncvec, buff[ib], buff[!ib], setup->e);
+ pffft_real_finalize(Ncvec, buff[ib], buff[!ib], setup->e.data());
}
else
{
@@ -1833,7 +1843,7 @@ void pffft_transform_internal(const PFFFT_Setup *setup, const v4sf *vinput, v4sf
uninterleave2(vinput[k*2], vinput[k*2+1], tmp[k*2], tmp[k*2+1]);
ib = (cfftf1_ps(Ncvec, buff[ib], buff[!ib], buff[ib], setup->twiddle, setup->ifac, -1.0f) == buff[1]);
- pffft_cplx_finalize(Ncvec, buff[ib], buff[!ib], setup->e);
+ pffft_cplx_finalize(Ncvec, buff[ib], buff[!ib], setup->e.data());
}
if(ordered)
pffft_zreorder(setup, reinterpret_cast<float*>(buff[!ib]),
@@ -1855,12 +1865,12 @@ void pffft_transform_internal(const PFFFT_Setup *setup, const v4sf *vinput, v4sf
}
if(setup->transform == PFFFT_REAL)
{
- pffft_real_preprocess(Ncvec, vinput, buff[ib], setup->e);
+ pffft_real_preprocess(Ncvec, vinput, buff[ib], setup->e.data());
ib = (rfftb1_ps(Ncvec*2, buff[ib], buff[0], buff[1], setup->twiddle, setup->ifac) == buff[1]);
}
else
{
- pffft_cplx_preprocess(Ncvec, vinput, buff[ib], setup->e);
+ pffft_cplx_preprocess(Ncvec, vinput, buff[ib], setup->e.data());
ib = (cfftf1_ps(Ncvec, buff[ib], buff[0], buff[1], setup->twiddle, setup->ifac, +1.0f) == buff[1]);
for(size_t k{0};k < Ncvec;++k)
interleave2(buff[ib][k*2], buff[ib][k*2+1], buff[ib][k*2], buff[ib][k*2+1]);
@@ -1899,8 +1909,8 @@ void pffft_zreorder(const PFFFT_Setup *setup, const float *in, float *out,
interleave2(vin[k*8 + 0], vin[k*8 + 1], vout[2*(0*dk + k) + 0], vout[2*(0*dk + k) + 1]);
interleave2(vin[k*8 + 4], vin[k*8 + 5], vout[2*(2*dk + k) + 0], vout[2*(2*dk + k) + 1]);
}
- reversed_copy(dk, vin+2, 8, vout + N/SIMD_SZ/2);
- reversed_copy(dk, vin+6, 8, vout + N/SIMD_SZ);
+ reversed_copy(dk, vin+2, 8, vout + N/SimdSize/2);
+ reversed_copy(dk, vin+6, 8, vout + N/SimdSize);
}
else
{
@@ -1909,8 +1919,8 @@ void pffft_zreorder(const PFFFT_Setup *setup, const float *in, float *out,
uninterleave2(vin[2*(0*dk + k) + 0], vin[2*(0*dk + k) + 1], vout[k*8 + 0], vout[k*8 + 1]);
uninterleave2(vin[2*(2*dk + k) + 0], vin[2*(2*dk + k) + 1], vout[k*8 + 4], vout[k*8 + 5]);
}
- unreversed_copy(dk, vin + N/SIMD_SZ/4, vout + N/SIMD_SZ - 6, -8);
- unreversed_copy(dk, vin + 3*N/SIMD_SZ/4, vout + N/SIMD_SZ - 2, -8);
+ unreversed_copy(dk, vin + N/SimdSize/4, vout + N/SimdSize - 6, -8);
+ unreversed_copy(dk, vin + 3_uz*N/SimdSize/4, vout + N/SimdSize - 2, -8);
}
}
else
diff --git a/common/pffft.h b/common/pffft.h
index 9cff9e54..cf356524 100644
--- a/common/pffft.h
+++ b/common/pffft.h
@@ -79,36 +79,32 @@
#ifndef PFFFT_H
#define PFFFT_H
-#include <stddef.h> // for size_t
-#include <stdint.h>
+#include <cstddef>
+#include <cstdint>
+#include <utility>
+
+#include "almalloc.h"
-#ifdef __cplusplus
-extern "C" {
-#endif
/* opaque struct holding internal stuff (precomputed twiddle factors) this
* struct can be shared by many threads as it contains only read-only data.
*/
-typedef struct PFFFT_Setup PFFFT_Setup;
-
-#ifndef PFFFT_COMMON_ENUMS
-#define PFFFT_COMMON_ENUMS
+struct PFFFT_Setup;
/* direction of the transform */
-typedef enum { PFFFT_FORWARD, PFFFT_BACKWARD } pffft_direction_t;
+enum pffft_direction_t { PFFFT_FORWARD, PFFFT_BACKWARD };
/* type of transform */
-typedef enum { PFFFT_REAL, PFFFT_COMPLEX } pffft_transform_t;
-
-#endif
+enum pffft_transform_t { PFFFT_REAL, PFFFT_COMPLEX };
/**
* Prepare for performing transforms of size N -- the returned PFFFT_Setup
* structure is read-only so it can safely be shared by multiple concurrent
* threads.
*/
-PFFFT_Setup *pffft_new_setup(unsigned int N, pffft_transform_t transform);
-void pffft_destroy_setup(PFFFT_Setup *setup);
+[[gnu::malloc]]
+gsl::owner<PFFFT_Setup*> pffft_new_setup(unsigned int N, pffft_transform_t transform);
+void pffft_destroy_setup(gsl::owner<PFFFT_Setup*> setup) noexcept;
/**
* Perform a Fourier transform. The z-domain data is stored in the most
@@ -174,19 +170,47 @@ void pffft_zconvolve_scale_accumulate(const PFFFT_Setup *setup, const float *dft
*/
void pffft_zconvolve_accumulate(const PFFFT_Setup *setup, const float *dft_a, const float *dft_b, float *dft_ab);
-/**
- * The float buffers must have the correct alignment (16-byte boundary on intel
- * and powerpc). This function may be used to obtain such correctly aligned
- * buffers.
- */
-void *pffft_aligned_malloc(size_t nb_bytes);
-void pffft_aligned_free(void *ptr);
-/* Return 4 or 1 depending if vectorization was enable when building pffft.cpp. */
-int pffft_simd_size();
+struct PFFFTSetup {
+ gsl::owner<PFFFT_Setup*> mSetup{};
+
+ PFFFTSetup() = default;
+ PFFFTSetup(const PFFFTSetup&) = delete;
+ PFFFTSetup(PFFFTSetup&& rhs) noexcept : mSetup{rhs.mSetup} { rhs.mSetup = nullptr; }
+ explicit PFFFTSetup(std::nullptr_t) noexcept { }
+ explicit PFFFTSetup(unsigned int n, pffft_transform_t transform)
+ : mSetup{pffft_new_setup(n, transform)}
+ { }
+ ~PFFFTSetup() { if(mSetup) pffft_destroy_setup(mSetup); }
+
+ PFFFTSetup& operator=(const PFFFTSetup&) = delete;
+ PFFFTSetup& operator=(PFFFTSetup&& rhs) noexcept
+ {
+ if(mSetup)
+ pffft_destroy_setup(mSetup);
+ mSetup = rhs.mSetup;
+ rhs.mSetup = nullptr;
+ return *this;
+ }
+
+ void transform(const float *input, float *output, float *work, pffft_direction_t direction) const
+ { pffft_transform(mSetup, input, output, work, direction); }
+
+ void transform_ordered(const float *input, float *output, float *work,
+ pffft_direction_t direction) const
+ { pffft_transform_ordered(mSetup, input, output, work, direction); }
+
+ void zreorder(const float *input, float *output, pffft_direction_t direction) const
+ { pffft_zreorder(mSetup, input, output, direction); }
+
+ void zconvolve_scale_accumulate(const float *dft_a, const float *dft_b, float *dft_ab,
+ float scaling) const
+ { pffft_zconvolve_scale_accumulate(mSetup, dft_a, dft_b, dft_ab, scaling); }
+
+ void zconvolve_accumulate(const float *dft_a, const float *dft_b, float *dft_ab) const
+ { pffft_zconvolve_accumulate(mSetup, dft_a, dft_b, dft_ab); }
-#ifdef __cplusplus
-}
-#endif
+ [[nodiscard]] operator bool() const noexcept { return mSetup != nullptr; }
+};
#endif // PFFFT_H
diff --git a/common/phase_shifter.h b/common/phase_shifter.h
index e1a83dab..1b3463de 100644
--- a/common/phase_shifter.h
+++ b/common/phase_shifter.h
@@ -10,6 +10,7 @@
#include <array>
#include <stddef.h>
#include <type_traits>
+#include <vector>
#include "alcomplex.h"
#include "alspan.h"
@@ -52,20 +53,19 @@ struct PhaseShifterT {
constexpr size_t fft_size{FilterSize};
constexpr size_t half_size{fft_size / 2};
- auto fftBuffer = std::make_unique<complex_d[]>(fft_size);
- std::fill_n(fftBuffer.get(), fft_size, complex_d{});
+ auto fftBuffer = std::vector<complex_d>(fft_size, complex_d{});
fftBuffer[half_size] = 1.0;
- forward_fft(al::span{fftBuffer.get(), fft_size});
+ forward_fft(al::span{fftBuffer});
fftBuffer[0] *= std::numeric_limits<double>::epsilon();
for(size_t i{1};i < half_size;++i)
fftBuffer[i] = complex_d{-fftBuffer[i].imag(), fftBuffer[i].real()};
fftBuffer[half_size] *= std::numeric_limits<double>::epsilon();
for(size_t i{half_size+1};i < fft_size;++i)
fftBuffer[i] = std::conj(fftBuffer[fft_size - i]);
- inverse_fft(al::span{fftBuffer.get(), fft_size});
+ inverse_fft(al::span{fftBuffer});
- auto fftiter = fftBuffer.get() + fft_size - 1;
+ auto fftiter = fftBuffer.data() + fft_size - 1;
for(float &coeff : mCoeffs)
{
coeff = static_cast<float>(fftiter->real() / double{fft_size});
diff --git a/common/polyphase_resampler.h b/common/polyphase_resampler.h
index 557485bb..764111c9 100644
--- a/common/polyphase_resampler.h
+++ b/common/polyphase_resampler.h
@@ -40,7 +40,7 @@ struct PPhaseResampler {
explicit operator bool() const noexcept { return !mF.empty(); }
private:
- uint mP, mQ, mM, mL;
+ uint mP{}, mQ{}, mM{}, mL{};
std::vector<double> mF;
};
diff --git a/common/ringbuffer.cpp b/common/ringbuffer.cpp
index af1f3669..2636bfb4 100644
--- a/common/ringbuffer.cpp
+++ b/common/ringbuffer.cpp
@@ -24,6 +24,8 @@
#include <algorithm>
#include <climits>
+#include <cstdint>
+#include <limits>
#include <stdexcept>
#include "almalloc.h"
@@ -40,7 +42,7 @@ RingBufferPtr RingBuffer::Create(std::size_t sz, std::size_t elem_sz, int limit_
power_of_two |= power_of_two>>4;
power_of_two |= power_of_two>>8;
power_of_two |= power_of_two>>16;
- if constexpr(SIZE_MAX > UINT_MAX)
+ if constexpr(sizeof(size_t) > sizeof(uint32_t))
power_of_two |= power_of_two>>32;
}
++power_of_two;
@@ -159,7 +161,7 @@ std::size_t RingBuffer::write(const void *src, std::size_t cnt) noexcept
}
-auto RingBuffer::getReadVector() const noexcept -> DataPair
+auto RingBuffer::getReadVector() noexcept -> DataPair
{
DataPair ret;
@@ -174,15 +176,15 @@ auto RingBuffer::getReadVector() const noexcept -> DataPair
{
/* Two part vector: the rest of the buffer after the current read ptr,
* plus some from the start of the buffer. */
- ret.first.buf = const_cast<std::byte*>(mBuffer.data() + r*mElemSize);
+ ret.first.buf = mBuffer.data() + r*mElemSize;
ret.first.len = mSizeMask+1 - r;
- ret.second.buf = const_cast<std::byte*>(mBuffer.data());
+ ret.second.buf = mBuffer.data();
ret.second.len = cnt2 & mSizeMask;
}
else
{
/* Single part vector: just the rest of the buffer */
- ret.first.buf = const_cast<std::byte*>(mBuffer.data() + r*mElemSize);
+ ret.first.buf = mBuffer.data() + r*mElemSize;
ret.first.len = free_cnt;
ret.second.buf = nullptr;
ret.second.len = 0;
@@ -191,7 +193,7 @@ auto RingBuffer::getReadVector() const noexcept -> DataPair
return ret;
}
-auto RingBuffer::getWriteVector() const noexcept -> DataPair
+auto RingBuffer::getWriteVector() noexcept -> DataPair
{
DataPair ret;
@@ -206,14 +208,14 @@ auto RingBuffer::getWriteVector() const noexcept -> DataPair
{
/* Two part vector: the rest of the buffer after the current write ptr,
* plus some from the start of the buffer. */
- ret.first.buf = const_cast<std::byte*>(mBuffer.data() + w*mElemSize);
+ ret.first.buf = mBuffer.data() + w*mElemSize;
ret.first.len = mSizeMask+1 - w;
- ret.second.buf = const_cast<std::byte*>(mBuffer.data());
+ ret.second.buf = mBuffer.data();
ret.second.len = cnt2 & mSizeMask;
}
else
{
- ret.first.buf = const_cast<std::byte*>(mBuffer.data() + w*mElemSize);
+ ret.first.buf = mBuffer.data() + w*mElemSize;
ret.first.len = free_cnt;
ret.second.buf = nullptr;
ret.second.len = 0;
diff --git a/common/ringbuffer.h b/common/ringbuffer.h
index 8c65c3af..ee59205a 100644
--- a/common/ringbuffer.h
+++ b/common/ringbuffer.h
@@ -7,6 +7,7 @@
#include <utility>
#include "almalloc.h"
+#include "flexarray.h"
/* NOTE: This lockless ringbuffer implementation is copied from JACK, extended
@@ -32,30 +33,29 @@ public:
};
using DataPair = std::pair<Data,Data>;
-
RingBuffer(const std::size_t count) : mBuffer{count} { }
/** Reset the read and write pointers to zero. This is not thread safe. */
- void reset() noexcept;
+ auto reset() noexcept -> void;
/**
* The non-copying data reader. Returns two ringbuffer data pointers that
* hold the current readable data. If the readable data is in one segment
* the second segment has zero length.
*/
- DataPair getReadVector() const noexcept;
+ [[nodiscard]] auto getReadVector() noexcept -> DataPair;
/**
* The non-copying data writer. Returns two ringbuffer data pointers that
* hold the current writeable data. If the writeable data is in one segment
* the second segment has zero length.
*/
- DataPair getWriteVector() const noexcept;
+ [[nodiscard]] auto getWriteVector() noexcept -> DataPair;
/**
* Return the number of elements available for reading. This is the number
* of elements in front of the read pointer and behind the write pointer.
*/
- std::size_t readSpace() const noexcept
+ [[nodiscard]] auto readSpace() const noexcept -> size_t
{
const size_t w{mWritePtr.load(std::memory_order_acquire)};
const size_t r{mReadPtr.load(std::memory_order_acquire)};
@@ -66,14 +66,14 @@ public:
* The copying data reader. Copy at most `cnt' elements into `dest'.
* Returns the actual number of elements copied.
*/
- std::size_t read(void *dest, std::size_t cnt) noexcept;
+ [[nodiscard]] auto read(void *dest, size_t cnt) noexcept -> size_t;
/**
* The copying data reader w/o read pointer advance. Copy at most `cnt'
* elements into `dest'. Returns the actual number of elements copied.
*/
- std::size_t peek(void *dest, std::size_t cnt) const noexcept;
+ [[nodiscard]] auto peek(void *dest, size_t cnt) const noexcept -> size_t;
/** Advance the read pointer `cnt' places. */
- void readAdvance(std::size_t cnt) noexcept
+ auto readAdvance(size_t cnt) noexcept -> void
{ mReadPtr.fetch_add(cnt, std::memory_order_acq_rel); }
@@ -81,7 +81,7 @@ public:
* Return the number of elements available for writing. This is the number
* of elements in front of the write pointer and behind the read pointer.
*/
- std::size_t writeSpace() const noexcept
+ [[nodiscard]] auto writeSpace() const noexcept -> size_t
{
const size_t w{mWritePtr.load(std::memory_order_acquire)};
const size_t r{mReadPtr.load(std::memory_order_acquire) + mWriteSize - mSizeMask};
@@ -92,12 +92,12 @@ public:
* The copying data writer. Copy at most `cnt' elements from `src'. Returns
* the actual number of elements copied.
*/
- std::size_t write(const void *src, std::size_t cnt) noexcept;
+ [[nodiscard]] auto write(const void *src, size_t cnt) noexcept -> size_t;
/** Advance the write pointer `cnt' places. */
- void writeAdvance(std::size_t cnt) noexcept
+ auto writeAdvance(size_t cnt) noexcept -> void
{ mWritePtr.fetch_add(cnt, std::memory_order_acq_rel); }
- std::size_t getElemSize() const noexcept { return mElemSize; }
+ [[nodiscard]] auto getElemSize() const noexcept -> size_t { return mElemSize; }
/**
* Create a new ringbuffer to hold at least `sz' elements of `elem_sz'
@@ -105,7 +105,8 @@ public:
* (even if it is already a power of two, to ensure the requested amount
* can be written).
*/
- static std::unique_ptr<RingBuffer> Create(std::size_t sz, std::size_t elem_sz, int limit_writes);
+ [[nodiscard]]
+ static auto Create(size_t sz, size_t elem_sz, int limit_writes) -> std::unique_ptr<RingBuffer>;
DEF_FAM_NEWDEL(RingBuffer, mBuffer)
};
diff --git a/common/vecmat.h b/common/vecmat.h
index a45f262f..0cdb82eb 100644
--- a/common/vecmat.h
+++ b/common/vecmat.h
@@ -14,7 +14,7 @@ namespace alu {
template<typename T>
class VectorR {
static_assert(std::is_floating_point<T>::value, "Must use floating-point types");
- alignas(16) T mVals[4];
+ alignas(16) std::array<T,4> mVals;
public:
constexpr VectorR() noexcept = default;
@@ -58,7 +58,7 @@ public:
return T{0};
}
- constexpr VectorR cross_product(const alu::VectorR<T> &rhs) const noexcept
+ [[nodiscard]] constexpr auto cross_product(const alu::VectorR<T> &rhs) const noexcept -> VectorR
{
return VectorR{
mVals[1]*rhs.mVals[2] - mVals[2]*rhs.mVals[1],
@@ -67,7 +67,7 @@ public:
T{0}};
}
- constexpr T dot_product(const alu::VectorR<T> &rhs) const noexcept
+ [[nodiscard]] constexpr auto dot_product(const alu::VectorR<T> &rhs) const noexcept -> T
{ return mVals[0]*rhs.mVals[0] + mVals[1]*rhs.mVals[1] + mVals[2]*rhs.mVals[2]; }
};
using Vector = VectorR<float>;
@@ -75,7 +75,7 @@ using Vector = VectorR<float>;
template<typename T>
class MatrixR {
static_assert(std::is_floating_point<T>::value, "Must use floating-point types");
- alignas(16) T mVals[16];
+ alignas(16) std::array<T,16> mVals;
public:
constexpr MatrixR() noexcept = default;
diff --git a/config.h.in b/config.h.in
index 20df5b46..19cb79e0 100644
--- a/config.h.in
+++ b/config.h.in
@@ -7,12 +7,6 @@
/* Define if HRTF data is embedded in the library */
#cmakedefine ALSOFT_EMBED_HRTF_DATA
-/* Define if we have the posix_memalign function */
-#cmakedefine HAVE_POSIX_MEMALIGN
-
-/* Define if we have the _aligned_malloc function */
-#cmakedefine HAVE__ALIGNED_MALLOC
-
/* Define if we have the proc_pidpath function */
#cmakedefine HAVE_PROC_PIDPATH
diff --git a/core/ambdec.cpp b/core/ambdec.cpp
index f98e1098..f3fe7566 100644
--- a/core/ambdec.cpp
+++ b/core/ambdec.cpp
@@ -42,8 +42,8 @@ enum class ReaderScope {
HFMatrix,
};
-#ifdef __USE_MINGW_ANSI_STDIO
-[[gnu::format(gnu_printf,2,3)]]
+#ifdef __MINGW32__
+[[gnu::format(__MINGW_PRINTF_FORMAT,2,3)]]
#else
[[gnu::format(printf,2,3)]]
#endif
@@ -53,7 +53,7 @@ std::optional<std::string> make_error(size_t linenum, const char *fmt, ...)
auto &str = ret.emplace();
str.resize(256);
- int printed{std::snprintf(const_cast<char*>(str.data()), str.length(), "Line %zu: ", linenum)};
+ int printed{std::snprintf(str.data(), str.length(), "Line %zu: ", linenum)};
if(printed < 0) printed = 0;
auto plen = std::min(static_cast<size_t>(printed), str.length());
@@ -111,7 +111,7 @@ std::optional<std::string> AmbDecConf::load(const char *fname) noexcept
{
if(command == "add_spkr")
{
- if(speaker_pos == NumSpeakers)
+ if(speaker_pos == Speakers.size())
return make_error(linenum, "Too many speakers specified");
AmbDecConf::SpeakerConf &spkr = Speakers[speaker_pos++];
@@ -145,7 +145,7 @@ std::optional<std::string> AmbDecConf::load(const char *fname) noexcept
}
else if(command == "add_row")
{
- if(pos == NumSpeakers)
+ if(pos == Speakers.size())
return make_error(linenum, "Too many matrix rows specified");
unsigned int mask{ChanMask};
@@ -205,12 +205,13 @@ std::optional<std::string> AmbDecConf::load(const char *fname) noexcept
}
else if(command == "/dec/speakers")
{
- if(NumSpeakers)
+ if(!Speakers.empty())
return make_error(linenum, "Duplicate speakers");
- istr >> NumSpeakers;
- if(!NumSpeakers)
- return make_error(linenum, "Invalid speakers: %zu", NumSpeakers);
- Speakers = std::make_unique<SpeakerConf[]>(NumSpeakers);
+ size_t numspeakers{};
+ istr >> numspeakers;
+ if(!numspeakers)
+ return make_error(linenum, "Invalid speakers: %zu", numspeakers);
+ Speakers.resize(numspeakers);
}
else if(command == "/dec/coeff_scale")
{
@@ -243,22 +244,22 @@ std::optional<std::string> AmbDecConf::load(const char *fname) noexcept
}
else if(command == "/speakers/{")
{
- if(!NumSpeakers)
+ if(Speakers.empty())
return make_error(linenum, "Speakers defined without a count");
scope = ReaderScope::Speakers;
}
else if(command == "/lfmatrix/{" || command == "/hfmatrix/{" || command == "/matrix/{")
{
- if(!NumSpeakers)
+ if(Speakers.empty())
return make_error(linenum, "Matrix defined without a speaker count");
if(!ChanMask)
return make_error(linenum, "Matrix defined without a channel mask");
- if(!Matrix)
+ if(Matrix.empty())
{
- Matrix = std::make_unique<CoeffArray[]>(NumSpeakers * FreqBands);
- LFMatrix = Matrix.get();
- HFMatrix = LFMatrix + NumSpeakers*(FreqBands-1);
+ Matrix.resize(Speakers.size() * FreqBands);
+ LFMatrix = Matrix.data();
+ HFMatrix = LFMatrix + Speakers.size()*(FreqBands-1);
}
if(FreqBands == 1)
@@ -285,8 +286,8 @@ std::optional<std::string> AmbDecConf::load(const char *fname) noexcept
if(!is_at_end(buffer, endpos))
return make_error(linenum, "Extra junk on end: %s", buffer.substr(endpos).c_str());
- if(speaker_pos < NumSpeakers || hfmatrix_pos < NumSpeakers
- || (FreqBands == 2 && lfmatrix_pos < NumSpeakers))
+ if(speaker_pos < Speakers.size() || hfmatrix_pos < Speakers.size()
+ || (FreqBands == 2 && lfmatrix_pos < Speakers.size()))
return make_error(linenum, "Incomplete decoder definition");
if(CoeffScale == AmbDecScale::Unset)
return make_error(linenum, "No coefficient scaling defined");
diff --git a/core/ambdec.h b/core/ambdec.h
index 19f68697..4305070f 100644
--- a/core/ambdec.h
+++ b/core/ambdec.h
@@ -5,6 +5,7 @@
#include <memory>
#include <optional>
#include <string>
+#include <vector>
#include "core/ambidefs.h"
@@ -34,17 +35,16 @@ struct AmbDecConf {
float Elevation{0.0f};
std::string Connection;
};
- size_t NumSpeakers{0};
- std::unique_ptr<SpeakerConf[]> Speakers;
+ std::vector<SpeakerConf> Speakers;
using CoeffArray = std::array<float,MaxAmbiChannels>;
- std::unique_ptr<CoeffArray[]> Matrix;
+ std::vector<CoeffArray> Matrix;
/* Unused when FreqBands == 1 */
- float LFOrderGain[MaxAmbiOrder+1]{};
+ std::array<float,MaxAmbiOrder+1> LFOrderGain{};
CoeffArray *LFMatrix;
- float HFOrderGain[MaxAmbiOrder+1]{};
+ std::array<float,MaxAmbiOrder+1> HFOrderGain{};
CoeffArray *HFMatrix;
~AmbDecConf();
diff --git a/core/async_event.h b/core/async_event.h
index f1ca0c7b..20857c9c 100644
--- a/core/async_event.h
+++ b/core/async_event.h
@@ -1,6 +1,7 @@
#ifndef CORE_EVENT_H
#define CORE_EVENT_H
+#include <array>
#include <stdint.h>
#include <variant>
@@ -39,7 +40,7 @@ struct AsyncBufferCompleteEvent {
};
struct AsyncDisconnectEvent {
- char msg[244];
+ std::array<char,244> msg;
};
struct AsyncEffectReleaseEvent {
diff --git a/core/bformatdec.cpp b/core/bformatdec.cpp
index a308e185..d6a44799 100644
--- a/core/bformatdec.cpp
+++ b/core/bformatdec.cpp
@@ -36,7 +36,7 @@ BFormatDec::BFormatDec(const size_t inchans, const al::span<const ChannelDec> co
auto &decoder = mChannelDec.emplace<std::vector<ChannelDecoderSingle>>(inchans);
for(size_t j{0};j < decoder.size();++j)
{
- float *outcoeffs{decoder[j].mGains};
+ float *outcoeffs{decoder[j].mGains.data()};
for(const ChannelDec &incoeffs : coeffs)
*(outcoeffs++) = incoeffs[j];
}
@@ -50,11 +50,11 @@ BFormatDec::BFormatDec(const size_t inchans, const al::span<const ChannelDec> co
for(size_t j{0};j < decoder.size();++j)
{
- float *outcoeffs{decoder[j].mGains[sHFBand]};
+ float *outcoeffs{decoder[j].mGains[sHFBand].data()};
for(const ChannelDec &incoeffs : coeffs)
*(outcoeffs++) = incoeffs[j];
- outcoeffs = decoder[j].mGains[sLFBand];
+ outcoeffs = decoder[j].mGains[sLFBand].data();
for(const ChannelDec &incoeffs : coeffslf)
*(outcoeffs++) = incoeffs[j];
}
@@ -76,8 +76,10 @@ void BFormatDec::process(const al::span<FloatBufferLine> OutBuffer,
{
chandec.mXOver.process({input->data(), SamplesToDo}, hfSamples.data(),
lfSamples.data());
- MixSamples(hfSamples, OutBuffer, chandec.mGains[sHFBand], chandec.mGains[sHFBand],0,0);
- MixSamples(lfSamples, OutBuffer, chandec.mGains[sLFBand], chandec.mGains[sLFBand],0,0);
+ MixSamples(hfSamples, OutBuffer, chandec.mGains[sHFBand].data(),
+ chandec.mGains[sHFBand].data(), 0, 0);
+ MixSamples(lfSamples, OutBuffer, chandec.mGains[sLFBand].data(),
+ chandec.mGains[sLFBand].data(), 0, 0);
++input;
}
};
@@ -86,8 +88,8 @@ void BFormatDec::process(const al::span<FloatBufferLine> OutBuffer,
auto *input = InSamples;
for(auto &chandec : decoder)
{
- MixSamples({input->data(), SamplesToDo}, OutBuffer, chandec.mGains, chandec.mGains,
- 0, 0);
+ MixSamples({input->data(), SamplesToDo}, OutBuffer, chandec.mGains.data(),
+ chandec.mGains.data(), 0, 0);
++input;
}
};
diff --git a/core/bformatdec.h b/core/bformatdec.h
index 3bb7f544..8513db03 100644
--- a/core/bformatdec.h
+++ b/core/bformatdec.h
@@ -25,15 +25,15 @@ class BFormatDec {
static constexpr size_t sNumBands{2};
struct ChannelDecoderSingle {
- float mGains[MAX_OUTPUT_CHANNELS];
+ std::array<float,MaxOutputChannels> mGains{};
};
struct ChannelDecoderDual {
BandSplitter mXOver;
- float mGains[sNumBands][MAX_OUTPUT_CHANNELS];
+ std::array<std::array<float,MaxOutputChannels>,sNumBands> mGains{};
};
- alignas(16) std::array<FloatBufferLine,2> mSamples;
+ alignas(16) std::array<FloatBufferLine,2> mSamples{};
const std::unique_ptr<FrontStablizer> mStablizer;
@@ -44,7 +44,7 @@ public:
const al::span<const ChannelDec> coeffslf, const float xover_f0norm,
std::unique_ptr<FrontStablizer> stablizer);
- bool hasStablizer() const noexcept { return mStablizer != nullptr; }
+ [[nodiscard]] auto hasStablizer() const noexcept -> bool { return mStablizer != nullptr; }
/* Decodes the ambisonic input to the given output channels. */
void process(const al::span<FloatBufferLine> OutBuffer, const FloatBufferLine *InSamples,
@@ -58,8 +58,6 @@ public:
static std::unique_ptr<BFormatDec> Create(const size_t inchans,
const al::span<const ChannelDec> coeffs, const al::span<const ChannelDec> coeffslf,
const float xover_f0norm, std::unique_ptr<FrontStablizer> stablizer);
-
- DEF_NEWDEL(BFormatDec)
};
#endif /* CORE_BFORMATDEC_H */
diff --git a/core/bs2b.cpp b/core/bs2b.cpp
index 303bf9bd..9157c4d7 100644
--- a/core/bs2b.cpp
+++ b/core/bs2b.cpp
@@ -26,72 +26,74 @@
#include <algorithm>
#include <cmath>
#include <iterator>
+#include <stdexcept>
#include "alnumbers.h"
#include "bs2b.h"
+namespace {
/* Set up all data. */
-static void init(struct bs2b *bs2b)
+void init(Bs2b::bs2b *bs2b)
{
float Fc_lo, Fc_hi;
float G_lo, G_hi;
- float x, g;
switch(bs2b->level)
{
- case BS2B_LOW_CLEVEL: /* Low crossfeed level */
+ case Bs2b::LowCLevel: /* Low crossfeed level */
Fc_lo = 360.0f;
Fc_hi = 501.0f;
G_lo = 0.398107170553497f;
G_hi = 0.205671765275719f;
break;
- case BS2B_MIDDLE_CLEVEL: /* Middle crossfeed level */
+ case Bs2b::MiddleCLevel: /* Middle crossfeed level */
Fc_lo = 500.0f;
Fc_hi = 711.0f;
G_lo = 0.459726988530872f;
G_hi = 0.228208484414988f;
break;
- case BS2B_HIGH_CLEVEL: /* High crossfeed level (virtual speakers are closer to itself) */
+ case Bs2b::HighCLevel: /* High crossfeed level (virtual speakers are closer to itself) */
Fc_lo = 700.0f;
Fc_hi = 1021.0f;
G_lo = 0.530884444230988f;
G_hi = 0.250105790667544f;
break;
- case BS2B_LOW_ECLEVEL: /* Low easy crossfeed level */
+ case Bs2b::LowECLevel: /* Low easy crossfeed level */
Fc_lo = 360.0f;
Fc_hi = 494.0f;
G_lo = 0.316227766016838f;
G_hi = 0.168236228897329f;
break;
- case BS2B_MIDDLE_ECLEVEL: /* Middle easy crossfeed level */
+ case Bs2b::MiddleECLevel: /* Middle easy crossfeed level */
Fc_lo = 500.0f;
Fc_hi = 689.0f;
G_lo = 0.354813389233575f;
G_hi = 0.187169483835901f;
break;
- default: /* High easy crossfeed level */
- bs2b->level = BS2B_HIGH_ECLEVEL;
+ case Bs2b::HighECLevel: /* High easy crossfeed level */
+ default:
+ bs2b->level = Bs2b::HighECLevel;
Fc_lo = 700.0f;
Fc_hi = 975.0f;
G_lo = 0.398107170553497f;
G_hi = 0.205671765275719f;
break;
- } /* switch */
+ }
- g = 1.0f / (1.0f - G_hi + G_lo);
+ float g{1.0f / (1.0f - G_hi + G_lo)};
/* $fc = $Fc / $s;
* $d = 1 / 2 / pi / $fc;
* $x = exp(-1 / $d);
*/
- x = std::exp(-al::numbers::pi_v<float>*2.0f*Fc_lo/static_cast<float>(bs2b->srate));
+ float x{ std::exp(-al::numbers::pi_v<float>*2.0f*Fc_lo/static_cast<float>(bs2b->srate))};
bs2b->b1_lo = x;
bs2b->a0_lo = G_lo * (1.0f - x) * g;
@@ -99,85 +101,84 @@ static void init(struct bs2b *bs2b)
bs2b->b1_hi = x;
bs2b->a0_hi = (1.0f - G_hi * (1.0f - x)) * g;
bs2b->a1_hi = -x * g;
-} /* init */
+}
+} // namespace
/* Exported functions.
* See descriptions in "bs2b.h"
*/
+namespace Bs2b {
-void bs2b_set_params(struct bs2b *bs2b, int level, int srate)
-{
- if(srate <= 0) srate = 1;
-
- bs2b->level = level;
- bs2b->srate = srate;
- init(bs2b);
-} /* bs2b_set_params */
-
-int bs2b_get_level(struct bs2b *bs2b)
+void bs2b::set_params(int level_, int srate_)
{
- return bs2b->level;
-} /* bs2b_get_level */
+ if(srate_ < 1)
+ throw std::runtime_error{"BS2B srate < 1"};
-int bs2b_get_srate(struct bs2b *bs2b)
-{
- return bs2b->srate;
-} /* bs2b_get_srate */
+ level = level_;
+ srate = srate_;
+ init(this);
+}
-void bs2b_clear(struct bs2b *bs2b)
+void bs2b::clear()
{
- std::fill(std::begin(bs2b->history), std::end(bs2b->history), bs2b::t_last_sample{});
-} /* bs2b_clear */
+ history.fill(bs2b::t_last_sample{});
+}
-void bs2b_cross_feed(struct bs2b *bs2b, float *Left, float *Right, size_t SamplesToDo)
+void bs2b::cross_feed(float *RESTRICT Left, float *RESTRICT Right, size_t SamplesToDo)
{
- const float a0_lo{bs2b->a0_lo};
- const float b1_lo{bs2b->b1_lo};
- const float a0_hi{bs2b->a0_hi};
- const float a1_hi{bs2b->a1_hi};
- const float b1_hi{bs2b->b1_hi};
- float lsamples[128][2];
- float rsamples[128][2];
+ const float a0lo{a0_lo};
+ const float b1lo{b1_lo};
+ const float a0hi{a0_hi};
+ const float a1hi{a1_hi};
+ const float b1hi{b1_hi};
+ std::array<std::array<float,2>,128> samples;
for(size_t base{0};base < SamplesToDo;)
{
- const size_t todo{std::min<size_t>(128, SamplesToDo-base)};
+ const size_t todo{std::min(samples.size(), SamplesToDo-base)};
/* Process left input */
- float z_lo{bs2b->history[0].lo};
- float z_hi{bs2b->history[0].hi};
+ float z_lo{history[0].lo};
+ float z_hi{history[0].hi};
for(size_t i{0};i < todo;i++)
{
- lsamples[i][0] = a0_lo*Left[i] + z_lo;
- z_lo = b1_lo*lsamples[i][0];
-
- lsamples[i][1] = a0_hi*Left[i] + z_hi;
- z_hi = a1_hi*Left[i] + b1_hi*lsamples[i][1];
+ const float x{Left[i]};
+ float y{a0hi*x + z_hi};
+ z_hi = a1hi*x + b1hi*y;
+ samples[i][0] = y;
+
+ y = a0lo*x + z_lo;
+ z_lo = b1lo*y;
+ samples[i][1] = y;
}
- bs2b->history[0].lo = z_lo;
- bs2b->history[0].hi = z_hi;
+ history[0].lo = z_lo;
+ history[0].hi = z_hi;
/* Process right input */
- z_lo = bs2b->history[1].lo;
- z_hi = bs2b->history[1].hi;
+ z_lo = history[1].lo;
+ z_hi = history[1].hi;
for(size_t i{0};i < todo;i++)
{
- rsamples[i][0] = a0_lo*Right[i] + z_lo;
- z_lo = b1_lo*rsamples[i][0];
-
- rsamples[i][1] = a0_hi*Right[i] + z_hi;
- z_hi = a1_hi*Right[i] + b1_hi*rsamples[i][1];
+ const float x{Right[i]};
+ float y{a0lo*x + z_lo};
+ z_lo = b1lo*y;
+ samples[i][0] += y;
+
+ y = a0hi*x + z_hi;
+ z_hi = a1hi*x + b1hi*y;
+ samples[i][1] += y;
}
- bs2b->history[1].lo = z_lo;
- bs2b->history[1].hi = z_hi;
+ history[1].lo = z_lo;
+ history[1].hi = z_hi;
- /* Crossfeed */
for(size_t i{0};i < todo;i++)
- *(Left++) = lsamples[i][1] + rsamples[i][0];
+ *(Left++) = samples[i][0];
for(size_t i{0};i < todo;i++)
- *(Right++) = rsamples[i][1] + lsamples[i][0];
+ *(Right++) = samples[i][1];
base += todo;
}
-} /* bs2b_cross_feed */
+}
+
+} // namespace Bs2b
diff --git a/core/bs2b.h b/core/bs2b.h
index 4d0b9dd8..6fb54c0c 100644
--- a/core/bs2b.h
+++ b/core/bs2b.h
@@ -24,66 +24,65 @@
#ifndef CORE_BS2B_H
#define CORE_BS2B_H
-#include "almalloc.h"
+#include <array>
-/* Number of crossfeed levels */
-#define BS2B_CLEVELS 3
+namespace Bs2b {
-/* Normal crossfeed levels */
-#define BS2B_HIGH_CLEVEL 3
-#define BS2B_MIDDLE_CLEVEL 2
-#define BS2B_LOW_CLEVEL 1
+enum {
+ /* Normal crossfeed levels */
+ LowCLevel = 1,
+ MiddleCLevel = 2,
+ HighCLevel = 3,
-/* Easy crossfeed levels */
-#define BS2B_HIGH_ECLEVEL BS2B_HIGH_CLEVEL + BS2B_CLEVELS
-#define BS2B_MIDDLE_ECLEVEL BS2B_MIDDLE_CLEVEL + BS2B_CLEVELS
-#define BS2B_LOW_ECLEVEL BS2B_LOW_CLEVEL + BS2B_CLEVELS
+ /* Easy crossfeed levels */
+ LowECLevel = 4,
+ MiddleECLevel = 5,
+ HighECLevel = 6,
-/* Default crossfeed levels */
-#define BS2B_DEFAULT_CLEVEL BS2B_HIGH_ECLEVEL
-/* Default sample rate (Hz) */
-#define BS2B_DEFAULT_SRATE 44100
+ DefaultCLevel = HighECLevel
+};
struct bs2b {
- int level; /* Crossfeed level */
- int srate; /* Sample rate (Hz) */
+ int level{}; /* Crossfeed level */
+ int srate{}; /* Sample rate (Hz) */
/* Lowpass IIR filter coefficients */
- float a0_lo;
- float b1_lo;
+ float a0_lo{};
+ float b1_lo{};
/* Highboost IIR filter coefficients */
- float a0_hi;
- float a1_hi;
- float b1_hi;
+ float a0_hi{};
+ float a1_hi{};
+ float b1_hi{};
/* Buffer of filter history
* [0] - first channel, [1] - second channel
*/
struct t_last_sample {
- float lo;
- float hi;
- } history[2];
-
- DEF_NEWDEL(bs2b)
-};
+ float lo{};
+ float hi{};
+ };
+ std::array<t_last_sample,2> history{};
+
+ /* Clear buffers and set new coefficients with new crossfeed level and
+ * sample rate values.
+ * level - crossfeed level of *Level enum values.
+ * srate - sample rate by Hz.
+ */
+ void set_params(int level, int srate);
-/* Clear buffers and set new coefficients with new crossfeed level and sample
- * rate values.
- * level - crossfeed level of *LEVEL values.
- * srate - sample rate by Hz.
- */
-void bs2b_set_params(bs2b *bs2b, int level, int srate);
+ /* Return current crossfeed level value */
+ [[nodiscard]] auto get_level() const noexcept -> int { return level; }
-/* Return current crossfeed level value */
-int bs2b_get_level(bs2b *bs2b);
+ /* Return current sample rate value */
+ [[nodiscard]] auto get_srate() const noexcept -> int { return srate; }
-/* Return current sample rate value */
-int bs2b_get_srate(bs2b *bs2b);
+ /* Clear buffer */
+ void clear();
-/* Clear buffer */
-void bs2b_clear(bs2b *bs2b);
+ void cross_feed(float *Left, float *Right, size_t SamplesToDo);
+};
-void bs2b_cross_feed(bs2b *bs2b, float *Left, float *Right, size_t SamplesToDo);
+} // namespace Bs2b
#endif /* CORE_BS2B_H */
diff --git a/core/bsinc_tables.cpp b/core/bsinc_tables.cpp
index 41102e9a..6e3ee338 100644
--- a/core/bsinc_tables.cpp
+++ b/core/bsinc_tables.cpp
@@ -5,9 +5,9 @@
#include <array>
#include <cassert>
#include <cmath>
+#include <cstddef>
#include <limits>
#include <memory>
-#include <stddef.h>
#include <stdexcept>
#include "alnumbers.h"
@@ -123,15 +123,13 @@ struct BSincHeader {
double beta{};
double scaleBase{};
- uint a[BSincScaleCount]{};
+ std::array<uint,BSincScaleCount> a{};
uint total_size{};
constexpr BSincHeader(uint Rejection, uint Order) noexcept
+ : width{CalcKaiserWidth(Rejection, Order)}, beta{CalcKaiserBeta(Rejection)}
+ , scaleBase{width / 2.0}
{
- width = CalcKaiserWidth(Rejection, Order);
- beta = CalcKaiserBeta(Rejection);
- scaleBase = width / 2.0;
-
uint num_points{Order+1};
for(uint si{0};si < BSincScaleCount;++si)
{
@@ -162,8 +160,9 @@ struct BSincFilterArray {
constexpr uint BSincPointsMax{(hdr.a[0]*2 + 3) & ~3u};
static_assert(BSincPointsMax <= MaxResamplerPadding, "MaxResamplerPadding is too small");
- using filter_type = double[BSincPhaseCount+1][BSincPointsMax];
- auto filter = std::make_unique<filter_type[]>(BSincScaleCount);
+ using filter_type = std::array<std::array<double,BSincPointsMax>,BSincPhaseCount+1>;
+ auto filterptr = std::make_unique<std::array<filter_type,BSincScaleCount>>();
+ const auto filter = filterptr->begin();
const double besseli_0_beta{cyl_bessel_i(0, hdr.beta)};
@@ -254,8 +253,8 @@ struct BSincFilterArray {
assert(idx == hdr.total_size);
}
- constexpr const BSincHeader &getHeader() const noexcept { return hdr; }
- constexpr const float *getTable() const noexcept { return &mTable.front(); }
+ [[nodiscard]] constexpr auto getHeader() const noexcept -> const BSincHeader& { return hdr; }
+ [[nodiscard]] constexpr auto getTable() const noexcept -> const float* { return mTable.data(); }
};
const BSincFilterArray<bsinc12_hdr> bsinc12_filter{};
diff --git a/core/bsinc_tables.h b/core/bsinc_tables.h
index aca4b274..6c33bd56 100644
--- a/core/bsinc_tables.h
+++ b/core/bsinc_tables.h
@@ -1,13 +1,15 @@
#ifndef CORE_BSINC_TABLES_H
#define CORE_BSINC_TABLES_H
+#include <array>
+
#include "bsinc_defs.h"
struct BSincTable {
float scaleBase, scaleRange;
- unsigned int m[BSincScaleCount];
- unsigned int filterOffset[BSincScaleCount];
+ std::array<unsigned int,BSincScaleCount> m;
+ std::array<unsigned int,BSincScaleCount> filterOffset;
const float *Tab;
};
diff --git a/core/buffer_storage.cpp b/core/buffer_storage.cpp
index 6ffab124..a343b946 100644
--- a/core/buffer_storage.cpp
+++ b/core/buffer_storage.cpp
@@ -3,7 +3,7 @@
#include "buffer_storage.h"
-#include <stdint.h>
+#include <cstdint>
const char *NameFromFormat(FmtType type) noexcept
diff --git a/core/buffer_storage.h b/core/buffer_storage.h
index 3b581b5e..dec774bf 100644
--- a/core/buffer_storage.h
+++ b/core/buffer_storage.h
@@ -98,19 +98,19 @@ struct BufferStorage {
AmbiScaling mAmbiScaling{AmbiScaling::FuMa};
uint mAmbiOrder{0u};
- inline uint bytesFromFmt() const noexcept { return BytesFromFmt(mType); }
- inline uint channelsFromFmt() const noexcept
+ [[nodiscard]] auto bytesFromFmt() const noexcept -> uint { return BytesFromFmt(mType); }
+ [[nodiscard]] auto channelsFromFmt() const noexcept -> uint
{ return ChannelsFromFmt(mChannels, mAmbiOrder); }
- inline uint frameSizeFromFmt() const noexcept { return channelsFromFmt() * bytesFromFmt(); }
+ [[nodiscard]] auto frameSizeFromFmt() const noexcept -> uint { return channelsFromFmt() * bytesFromFmt(); }
- inline uint blockSizeFromFmt() const noexcept
+ [[nodiscard]] auto blockSizeFromFmt() const noexcept -> uint
{
if(mType == FmtIMA4) return ((mBlockAlign-1)/2 + 4) * channelsFromFmt();
if(mType == FmtMSADPCM) return ((mBlockAlign-2)/2 + 7) * channelsFromFmt();
return frameSizeFromFmt();
};
- inline bool isBFormat() const noexcept { return IsBFormat(mChannels); }
+ [[nodiscard]] auto isBFormat() const noexcept -> bool { return IsBFormat(mChannels); }
};
#endif /* CORE_BUFFER_STORAGE_H */
diff --git a/core/context.cpp b/core/context.cpp
index 2ebbc7b1..0fe50d25 100644
--- a/core/context.cpp
+++ b/core/context.cpp
@@ -2,6 +2,7 @@
#include "config.h"
#include <cassert>
+#include <functional>
#include <limits>
#include <memory>
#include <stdexcept>
@@ -26,43 +27,14 @@ ContextBase::ContextBase(DeviceBase *device) : mDevice{device}
ContextBase::~ContextBase()
{
- size_t count{0};
- ContextProps *cprops{mParams.ContextUpdate.exchange(nullptr, std::memory_order_relaxed)};
- if(cprops)
- {
- ++count;
- delete cprops;
- }
- cprops = mFreeContextProps.exchange(nullptr, std::memory_order_acquire);
- while(cprops)
- {
- std::unique_ptr<ContextProps> old{cprops};
- cprops = old->next.load(std::memory_order_relaxed);
- ++count;
- }
- TRACE("Freed %zu context property object%s\n", count, (count==1)?"":"s");
-
- count = 0;
- EffectSlotProps *eprops{mFreeEffectslotProps.exchange(nullptr, std::memory_order_acquire)};
- while(eprops)
- {
- std::unique_ptr<EffectSlotProps> old{eprops};
- eprops = old->next.load(std::memory_order_relaxed);
- ++count;
- }
- TRACE("Freed %zu AuxiliaryEffectSlot property object%s\n", count, (count==1)?"":"s");
-
- if(EffectSlotArray *curarray{mActiveAuxSlots.exchange(nullptr, std::memory_order_relaxed)})
- {
+ if(std::unique_ptr<EffectSlotArray> curarray{mActiveAuxSlots.exchange(nullptr, std::memory_order_relaxed)})
std::destroy_n(curarray->end(), curarray->size());
- delete curarray;
- }
- delete mVoices.exchange(nullptr, std::memory_order_relaxed);
+ mVoices.store(nullptr, std::memory_order_relaxed);
if(mAsyncEvents)
{
- count = 0;
+ size_t count{0};
auto evt_vec = mAsyncEvents->getReadVector();
if(evt_vec.first.len > 0)
{
@@ -85,85 +57,131 @@ ContextBase::~ContextBase()
void ContextBase::allocVoiceChanges()
{
- constexpr size_t clustersize{128};
+ static constexpr size_t clustersize{std::tuple_size_v<VoiceChangeCluster::element_type>};
+
+ VoiceChangeCluster clusterptr{std::make_unique<VoiceChangeCluster::element_type>()};
+ const auto cluster = al::span{*clusterptr};
- VoiceChangeCluster cluster{std::make_unique<VoiceChange[]>(clustersize)};
for(size_t i{1};i < clustersize;++i)
cluster[i-1].mNext.store(std::addressof(cluster[i]), std::memory_order_relaxed);
cluster[clustersize-1].mNext.store(mVoiceChangeTail, std::memory_order_relaxed);
- mVoiceChangeClusters.emplace_back(std::move(cluster));
- mVoiceChangeTail = mVoiceChangeClusters.back().get();
+ mVoiceChangeClusters.emplace_back(std::move(clusterptr));
+ mVoiceChangeTail = mVoiceChangeClusters.back()->data();
}
void ContextBase::allocVoiceProps()
{
- constexpr size_t clustersize{32};
+ static constexpr size_t clustersize{std::tuple_size_v<VoicePropsCluster::element_type>};
TRACE("Increasing allocated voice properties to %zu\n",
(mVoicePropClusters.size()+1) * clustersize);
- VoicePropsCluster cluster{std::make_unique<VoicePropsItem[]>(clustersize)};
+ auto clusterptr = std::make_unique<VoicePropsCluster::element_type>();
+ auto cluster = al::span{*clusterptr};
for(size_t i{1};i < clustersize;++i)
cluster[i-1].next.store(std::addressof(cluster[i]), std::memory_order_relaxed);
- mVoicePropClusters.emplace_back(std::move(cluster));
+ mVoicePropClusters.emplace_back(std::move(clusterptr));
VoicePropsItem *oldhead{mFreeVoiceProps.load(std::memory_order_acquire)};
do {
- mVoicePropClusters.back()[clustersize-1].next.store(oldhead, std::memory_order_relaxed);
- } while(mFreeVoiceProps.compare_exchange_weak(oldhead, mVoicePropClusters.back().get(),
+ mVoicePropClusters.back()->back().next.store(oldhead, std::memory_order_relaxed);
+ } while(mFreeVoiceProps.compare_exchange_weak(oldhead, mVoicePropClusters.back()->data(),
std::memory_order_acq_rel, std::memory_order_acquire) == false);
}
void ContextBase::allocVoices(size_t addcount)
{
- constexpr size_t clustersize{32};
+ static constexpr size_t clustersize{std::tuple_size_v<VoiceCluster::element_type>};
/* Convert element count to cluster count. */
addcount = (addcount+(clustersize-1)) / clustersize;
+ if(!addcount)
+ {
+ if(!mVoiceClusters.empty())
+ return;
+ ++addcount;
+ }
+
if(addcount >= std::numeric_limits<int>::max()/clustersize - mVoiceClusters.size())
throw std::runtime_error{"Allocating too many voices"};
const size_t totalcount{(mVoiceClusters.size()+addcount) * clustersize};
TRACE("Increasing allocated voices to %zu\n", totalcount);
- auto newarray = VoiceArray::Create(totalcount);
while(addcount)
{
- mVoiceClusters.emplace_back(std::make_unique<Voice[]>(clustersize));
+ mVoiceClusters.emplace_back(std::make_unique<VoiceCluster::element_type>());
--addcount;
}
+ auto newarray = VoiceArray::Create(totalcount);
auto voice_iter = newarray->begin();
for(VoiceCluster &cluster : mVoiceClusters)
- {
- for(size_t i{0};i < clustersize;++i)
- *(voice_iter++) = &cluster[i];
- }
+ voice_iter = std::transform(cluster->begin(), cluster->end(), voice_iter,
+ [](Voice &voice) noexcept -> Voice* { return &voice; });
- if(auto *oldvoices = mVoices.exchange(newarray.release(), std::memory_order_acq_rel))
- {
- mDevice->waitForMix();
- delete oldvoices;
- }
+ if(auto oldvoices = mVoices.exchange(std::move(newarray), std::memory_order_acq_rel))
+ std::ignore = mDevice->waitForMix();
}
+void ContextBase::allocEffectSlotProps()
+{
+ static constexpr size_t clustersize{std::tuple_size_v<EffectSlotPropsCluster::element_type>};
+
+ TRACE("Increasing allocated effect slot properties to %zu\n",
+ (mEffectSlotPropClusters.size()+1) * clustersize);
+
+ auto clusterptr = std::make_unique<EffectSlotPropsCluster::element_type>();
+ auto cluster = al::span{*clusterptr};
+ for(size_t i{1};i < clustersize;++i)
+ cluster[i-1].next.store(std::addressof(cluster[i]), std::memory_order_relaxed);
+ auto *newcluster = mEffectSlotPropClusters.emplace_back(std::move(clusterptr)).get();
+
+ EffectSlotProps *oldhead{mFreeEffectSlotProps.load(std::memory_order_acquire)};
+ do {
+ newcluster->back().next.store(oldhead, std::memory_order_relaxed);
+ } while(mFreeEffectSlotProps.compare_exchange_weak(oldhead, newcluster->data(),
+ std::memory_order_acq_rel, std::memory_order_acquire) == false);
+}
+
EffectSlot *ContextBase::getEffectSlot()
{
- for(auto& cluster : mEffectSlotClusters)
+ for(auto& clusterptr : mEffectSlotClusters)
{
- for(size_t i{0};i < EffectSlotClusterSize;++i)
- {
- if(!cluster[i].InUse)
- return &cluster[i];
- }
+ const auto cluster = al::span{*clusterptr};
+ auto iter = std::find_if_not(cluster.begin(), cluster.end(),
+ std::mem_fn(&EffectSlot::InUse));
+ if(iter != cluster.end()) return al::to_address(iter);
}
- if(1 >= std::numeric_limits<int>::max()/EffectSlotClusterSize - mEffectSlotClusters.size())
+ auto clusterptr = std::make_unique<EffectSlotCluster::element_type>();
+ if(1 >= std::numeric_limits<int>::max()/clusterptr->size() - mEffectSlotClusters.size())
throw std::runtime_error{"Allocating too many effect slots"};
- const size_t totalcount{(mEffectSlotClusters.size()+1) * EffectSlotClusterSize};
+ const size_t totalcount{(mEffectSlotClusters.size()+1) * clusterptr->size()};
TRACE("Increasing allocated effect slots to %zu\n", totalcount);
- mEffectSlotClusters.emplace_back(std::make_unique<EffectSlot[]>(EffectSlotClusterSize));
- return getEffectSlot();
+ mEffectSlotClusters.emplace_back(std::move(clusterptr));
+ return mEffectSlotClusters.back()->data();
+}
+
+
+void ContextBase::allocContextProps()
+{
+ static constexpr size_t clustersize{std::tuple_size_v<ContextPropsCluster::element_type>};
+
+ TRACE("Increasing allocated context properties to %zu\n",
+ (mContextPropClusters.size()+1) * clustersize);
+
+ auto clusterptr = std::make_unique<ContextPropsCluster::element_type>();
+ auto cluster = al::span{*clusterptr};
+ for(size_t i{1};i < clustersize;++i)
+ cluster[i-1].next.store(std::addressof(cluster[i]), std::memory_order_relaxed);
+ auto *newcluster = mContextPropClusters.emplace_back(std::move(clusterptr)).get();
+
+ ContextProps *oldhead{mFreeContextProps.load(std::memory_order_acquire)};
+ do {
+ newcluster->back().next.store(oldhead, std::memory_order_relaxed);
+ } while(mFreeContextProps.compare_exchange_weak(oldhead, newcluster->data(),
+ std::memory_order_acq_rel, std::memory_order_acquire) == false);
}
diff --git a/core/context.h b/core/context.h
index ccb7dd3b..980514b3 100644
--- a/core/context.h
+++ b/core/context.h
@@ -14,6 +14,7 @@
#include "alspan.h"
#include "async_event.h"
#include "atomic.h"
+#include "flexarray.h"
#include "opthelpers.h"
#include "vecmat.h"
@@ -26,9 +27,9 @@ struct VoiceChange;
struct VoicePropsItem;
-constexpr float SpeedOfSoundMetersPerSec{343.3f};
+inline constexpr float SpeedOfSoundMetersPerSec{343.3f};
-constexpr float AirAbsorbGainHF{0.99426f}; /* -0.05dB */
+inline constexpr float AirAbsorbGainHF{0.99426f}; /* -0.05dB */
enum class DistanceModel : unsigned char {
Disable,
@@ -56,8 +57,6 @@ struct ContextProps {
DistanceModel mDistanceModel;
std::atomic<ContextProps*> next;
-
- DEF_NEWDEL(ContextProps)
};
struct ContextParams {
@@ -85,7 +84,7 @@ struct ContextBase {
/* Counter for the pre-mixing updates, in 31.1 fixed point (lowest bit
* indicates if updates are currently happening).
*/
- RefCount mUpdateCount{0u};
+ std::atomic<unsigned int> mUpdateCount{0u};
std::atomic<bool> mHoldUpdates{false};
std::atomic<bool> mStopVoicesOnDisconnect{true};
@@ -96,7 +95,7 @@ struct ContextBase {
*/
std::atomic<ContextProps*> mFreeContextProps{nullptr};
std::atomic<VoicePropsItem*> mFreeVoiceProps{nullptr};
- std::atomic<EffectSlotProps*> mFreeEffectslotProps{nullptr};
+ std::atomic<EffectSlotProps*> mFreeEffectSlotProps{nullptr};
/* The voice change tail is the beginning of the "free" elements, up to and
* *excluding* the current. If tail==current, there's no free elements and
@@ -108,21 +107,22 @@ struct ContextBase {
void allocVoiceChanges();
void allocVoiceProps();
-
+ void allocEffectSlotProps();
+ void allocContextProps();
ContextParams mParams;
using VoiceArray = al::FlexArray<Voice*>;
- std::atomic<VoiceArray*> mVoices{};
+ al::atomic_unique_ptr<VoiceArray> mVoices{};
std::atomic<size_t> mActiveVoiceCount{};
void allocVoices(size_t addcount);
- al::span<Voice*> getVoicesSpan() const noexcept
+ [[nodiscard]] auto getVoicesSpan() const noexcept -> al::span<Voice*>
{
return {mVoices.load(std::memory_order_relaxed)->data(),
mActiveVoiceCount.load(std::memory_order_relaxed)};
}
- al::span<Voice*> getVoicesSpanAcquired() const noexcept
+ [[nodiscard]] auto getVoicesSpanAcquired() const noexcept -> al::span<Voice*>
{
return {mVoices.load(std::memory_order_acquire)->data(),
mActiveVoiceCount.load(std::memory_order_acquire)};
@@ -143,22 +143,30 @@ struct ContextBase {
* However, to avoid allocating each object individually, they're allocated
* in clusters that are stored in a vector for easy automatic cleanup.
*/
- using VoiceChangeCluster = std::unique_ptr<VoiceChange[]>;
+ using VoiceChangeCluster = std::unique_ptr<std::array<VoiceChange,128>>;
std::vector<VoiceChangeCluster> mVoiceChangeClusters;
- using VoiceCluster = std::unique_ptr<Voice[]>;
+ using VoiceCluster = std::unique_ptr<std::array<Voice,32>>;
std::vector<VoiceCluster> mVoiceClusters;
- using VoicePropsCluster = std::unique_ptr<VoicePropsItem[]>;
+ using VoicePropsCluster = std::unique_ptr<std::array<VoicePropsItem,32>>;
std::vector<VoicePropsCluster> mVoicePropClusters;
- static constexpr size_t EffectSlotClusterSize{4};
EffectSlot *getEffectSlot();
- using EffectSlotCluster = std::unique_ptr<EffectSlot[]>;
+ using EffectSlotCluster = std::unique_ptr<std::array<EffectSlot,4>>;
std::vector<EffectSlotCluster> mEffectSlotClusters;
+ using EffectSlotPropsCluster = std::unique_ptr<std::array<EffectSlotProps,4>>;
+ std::vector<EffectSlotPropsCluster> mEffectSlotPropClusters;
+
+ /* This could be greater than 2, but there should be no way there can be
+ * more than two context property updates in use simultaneously.
+ */
+ using ContextPropsCluster = std::unique_ptr<std::array<ContextProps,2>>;
+ std::vector<ContextPropsCluster> mContextPropClusters;
+
ContextBase(DeviceBase *device);
ContextBase(const ContextBase&) = delete;
diff --git a/core/converter.cpp b/core/converter.cpp
index 5b2f3e15..805b8548 100644
--- a/core/converter.cpp
+++ b/core/converter.cpp
@@ -9,7 +9,7 @@
#include <cstddef>
#include <cstdint>
#include <iterator>
-#include <limits.h>
+#include <climits>
#include "albit.h"
#include "alnumeric.h"
@@ -24,26 +24,23 @@ static_assert((BufferLineSize-1)/MaxPitch > 0, "MaxPitch is too large for Buffer
static_assert((INT_MAX>>MixerFracBits)/MaxPitch > BufferLineSize,
"MaxPitch and/or BufferLineSize are too large for MixerFracBits!");
-/* Base template left undefined. Should be marked =delete, but Clang 3.8.1
- * chokes on that given the inline specializations.
- */
template<DevFmtType T>
-inline float LoadSample(DevFmtType_t<T> val) noexcept;
+constexpr float LoadSample(DevFmtType_t<T> val) noexcept = delete;
-template<> inline float LoadSample<DevFmtByte>(DevFmtType_t<DevFmtByte> val) noexcept
-{ return val * (1.0f/128.0f); }
-template<> inline float LoadSample<DevFmtShort>(DevFmtType_t<DevFmtShort> val) noexcept
-{ return val * (1.0f/32768.0f); }
-template<> inline float LoadSample<DevFmtInt>(DevFmtType_t<DevFmtInt> val) noexcept
+template<> constexpr float LoadSample<DevFmtByte>(DevFmtType_t<DevFmtByte> val) noexcept
+{ return float(val) * (1.0f/128.0f); }
+template<> constexpr float LoadSample<DevFmtShort>(DevFmtType_t<DevFmtShort> val) noexcept
+{ return float(val) * (1.0f/32768.0f); }
+template<> constexpr float LoadSample<DevFmtInt>(DevFmtType_t<DevFmtInt> val) noexcept
{ return static_cast<float>(val) * (1.0f/2147483648.0f); }
-template<> inline float LoadSample<DevFmtFloat>(DevFmtType_t<DevFmtFloat> val) noexcept
+template<> constexpr float LoadSample<DevFmtFloat>(DevFmtType_t<DevFmtFloat> val) noexcept
{ return val; }
-template<> inline float LoadSample<DevFmtUByte>(DevFmtType_t<DevFmtUByte> val) noexcept
+template<> constexpr float LoadSample<DevFmtUByte>(DevFmtType_t<DevFmtUByte> val) noexcept
{ return LoadSample<DevFmtByte>(static_cast<int8_t>(val - 128)); }
-template<> inline float LoadSample<DevFmtUShort>(DevFmtType_t<DevFmtUShort> val) noexcept
+template<> constexpr float LoadSample<DevFmtUShort>(DevFmtType_t<DevFmtUShort> val) noexcept
{ return LoadSample<DevFmtShort>(static_cast<int16_t>(val - 32768)); }
-template<> inline float LoadSample<DevFmtUInt>(DevFmtType_t<DevFmtUInt> val) noexcept
+template<> constexpr float LoadSample<DevFmtUInt>(DevFmtType_t<DevFmtUInt> val) noexcept
{ return LoadSample<DevFmtInt>(static_cast<int32_t>(val - 2147483648u)); }
@@ -51,7 +48,7 @@ template<DevFmtType T>
inline void LoadSampleArray(float *RESTRICT dst, const void *src, const size_t srcstep,
const size_t samples) noexcept
{
- const DevFmtType_t<T> *ssrc = static_cast<const DevFmtType_t<T>*>(src);
+ auto *ssrc = static_cast<const DevFmtType_t<T>*>(src);
for(size_t i{0u};i < samples;i++)
dst[i] = LoadSample<T>(ssrc[i*srcstep]);
}
@@ -99,7 +96,7 @@ template<DevFmtType T>
inline void StoreSampleArray(void *dst, const float *RESTRICT src, const size_t dststep,
const size_t samples) noexcept
{
- DevFmtType_t<T> *sdst = static_cast<DevFmtType_t<T>*>(dst);
+ auto *sdst = static_cast<DevFmtType_t<T>*>(dst);
for(size_t i{0u};i < samples;i++)
sdst[i*dststep] = StoreSample<T>(src[i]);
}
@@ -127,7 +124,7 @@ void StoreSamples(void *dst, const float *src, const size_t dststep, const DevFm
template<DevFmtType T>
void Mono2Stereo(float *RESTRICT dst, const void *src, const size_t frames) noexcept
{
- const DevFmtType_t<T> *ssrc = static_cast<const DevFmtType_t<T>*>(src);
+ auto *ssrc = static_cast<const DevFmtType_t<T>*>(src);
for(size_t i{0u};i < frames;i++)
dst[i*2 + 1] = dst[i*2 + 0] = LoadSample<T>(ssrc[i]) * 0.707106781187f;
}
@@ -136,7 +133,7 @@ template<DevFmtType T>
void Multi2Mono(uint chanmask, const size_t step, const float scale, float *RESTRICT dst,
const void *src, const size_t frames) noexcept
{
- const DevFmtType_t<T> *ssrc = static_cast<const DevFmtType_t<T>*>(src);
+ auto *ssrc = static_cast<const DevFmtType_t<T>*>(src);
std::fill_n(dst, frames, 0.0f);
for(size_t c{0};chanmask;++c)
{
@@ -216,8 +213,8 @@ uint SampleConverter::availableOut(uint srcframes) const
uint SampleConverter::convert(const void **src, uint *srcframes, void *dst, uint dstframes)
{
- const uint SrcFrameSize{static_cast<uint>(mChan.size()) * mSrcTypeSize};
- const uint DstFrameSize{static_cast<uint>(mChan.size()) * mDstTypeSize};
+ const size_t SrcFrameSize{mChan.size() * mSrcTypeSize};
+ const size_t DstFrameSize{mChan.size() * mDstTypeSize};
const uint increment{mIncrement};
auto SamplesIn = static_cast<const std::byte*>(*src);
uint NumSrcSamples{*srcframes};
@@ -243,8 +240,8 @@ uint SampleConverter::convert(const void **src, uint *srcframes, void *dst, uint
break;
}
- float *RESTRICT SrcData{mSrcSamples};
- float *RESTRICT DstData{mDstSamples};
+ float *RESTRICT SrcData{mSrcSamples.data()};
+ float *RESTRICT DstData{mDstSamples.data()};
uint DataPosFrac{mFracOffset};
uint64_t DataSize64{prepcount};
DataSize64 += readable;
@@ -271,13 +268,13 @@ uint SampleConverter::convert(const void **src, uint *srcframes, void *dst, uint
/* Load the previous samples into the source data first, then the
* new samples from the input buffer.
*/
- std::copy_n(mChan[chan].PrevSamples, prepcount, SrcData);
+ std::copy_n(mChan[chan].PrevSamples.cbegin(), prepcount, SrcData);
LoadSamples(SrcData + prepcount, SrcSamples, mChan.size(), mSrcType, readable);
/* Store as many prep samples for next time as possible, given the
* number of output samples being generated.
*/
- std::copy_n(SrcData+SrcDataEnd, nextprep, mChan[chan].PrevSamples);
+ std::copy_n(SrcData+SrcDataEnd, nextprep, mChan[chan].PrevSamples.begin());
std::fill(std::begin(mChan[chan].PrevSamples)+nextprep,
std::end(mChan[chan].PrevSamples), 0.0f);
@@ -328,9 +325,9 @@ uint SampleConverter::convertPlanar(const void **src, uint *srcframes, void *con
*/
for(size_t chan{0u};chan < mChan.size();chan++)
{
- LoadSamples(&mChan[chan].PrevSamples[prepcount],
- static_cast<const std::byte*>(src[chan]), 1, mSrcType, readable);
- src[chan] = static_cast<const std::byte*>(src[chan]) + mSrcTypeSize*readable;
+ auto *samples = static_cast<const std::byte*>(src[chan]);
+ LoadSamples(&mChan[chan].PrevSamples[prepcount], samples, 1, mSrcType, readable);
+ src[chan] = samples + size_t{mSrcTypeSize}*readable;
}
mSrcPrepCount = prepcount + readable;
@@ -338,8 +335,8 @@ uint SampleConverter::convertPlanar(const void **src, uint *srcframes, void *con
break;
}
- float *RESTRICT SrcData{mSrcSamples};
- float *RESTRICT DstData{mDstSamples};
+ float *RESTRICT SrcData{mSrcSamples.data()};
+ float *RESTRICT DstData{mDstSamples.data()};
uint DataPosFrac{mFracOffset};
uint64_t DataSize64{prepcount};
DataSize64 += readable;
@@ -363,13 +360,13 @@ uint SampleConverter::convertPlanar(const void **src, uint *srcframes, void *con
/* Load the previous samples into the source data first, then the
* new samples from the input buffer.
*/
- std::copy_n(mChan[chan].PrevSamples, prepcount, SrcData);
+ std::copy_n(mChan[chan].PrevSamples.cbegin(), prepcount, SrcData);
LoadSamples(SrcData + prepcount, src[chan], 1, mSrcType, readable);
/* Store as many prep samples for next time as possible, given the
* number of output samples being generated.
*/
- std::copy_n(SrcData+SrcDataEnd, nextprep, mChan[chan].PrevSamples);
+ std::copy_n(SrcData+SrcDataEnd, nextprep, mChan[chan].PrevSamples.begin());
std::fill(std::begin(mChan[chan].PrevSamples)+nextprep,
std::end(mChan[chan].PrevSamples), 0.0f);
@@ -377,7 +374,7 @@ uint SampleConverter::convertPlanar(const void **src, uint *srcframes, void *con
mResample(&mState, SrcData+MaxResamplerEdge, DataPosFrac, increment,
{DstData, DstSize});
- std::byte *DstSamples = static_cast<std::byte*>(dst[chan]) + pos*mDstTypeSize;
+ auto *DstSamples = static_cast<std::byte*>(dst[chan]) + pos*size_t{mDstTypeSize};
StoreSamples(DstSamples, DstData, 1, mDstType, DstSize);
}
@@ -390,7 +387,7 @@ uint SampleConverter::convertPlanar(const void **src, uint *srcframes, void *con
/* Update the src and dst pointers in case there's still more to do. */
const uint srcread{minu(NumSrcSamples, SrcDataEnd + mSrcPrepCount - prepcount)};
for(size_t chan{0u};chan < mChan.size();chan++)
- src[chan] = static_cast<const std::byte*>(src[chan]) + mSrcTypeSize*srcread;
+ src[chan] = static_cast<const std::byte*>(src[chan]) + size_t{mSrcTypeSize}*srcread;
NumSrcSamples -= srcread;
pos += DstSize;
diff --git a/core/converter.h b/core/converter.h
index 49ca124d..3dc2babb 100644
--- a/core/converter.h
+++ b/core/converter.h
@@ -7,6 +7,7 @@
#include "almalloc.h"
#include "devformat.h"
+#include "flexarray.h"
#include "mixer/defs.h"
using uint = unsigned int;
@@ -25,22 +26,22 @@ struct SampleConverter {
InterpState mState{};
ResamplerFunc mResample{};
- alignas(16) float mSrcSamples[BufferLineSize]{};
- alignas(16) float mDstSamples[BufferLineSize]{};
+ alignas(16) FloatBufferLine mSrcSamples{};
+ alignas(16) FloatBufferLine mDstSamples{};
struct ChanSamples {
- alignas(16) float PrevSamples[MaxResamplerPadding];
+ alignas(16) std::array<float,MaxResamplerPadding> PrevSamples;
};
al::FlexArray<ChanSamples> mChan;
SampleConverter(size_t numchans) : mChan{numchans} { }
- uint convert(const void **src, uint *srcframes, void *dst, uint dstframes);
- uint convertPlanar(const void **src, uint *srcframes, void *const*dst, uint dstframes);
- uint availableOut(uint srcframes) const;
+ [[nodiscard]] auto convert(const void **src, uint *srcframes, void *dst, uint dstframes) -> uint;
+ [[nodiscard]] auto convertPlanar(const void **src, uint *srcframes, void *const*dst, uint dstframes) -> uint;
+ [[nodiscard]] auto availableOut(uint srcframes) const -> uint;
using SampleOffset = std::chrono::duration<int64_t, std::ratio<1,MixerFracOne>>;
- SampleOffset currentInputDelay() const noexcept
+ [[nodiscard]] auto currentInputDelay() const noexcept -> SampleOffset
{
const int64_t prep{int64_t{mSrcPrepCount} - MaxResamplerEdge};
return SampleOffset{(prep<<MixerFracBits) + mFracOffset};
@@ -59,7 +60,7 @@ struct ChannelConverter {
uint mChanMask{};
DevFmtChannels mDstChans{};
- bool is_active() const noexcept { return mChanMask != 0; }
+ [[nodiscard]] auto is_active() const noexcept -> bool { return mChanMask != 0; }
void convert(const void *src, float *dst, uint frames) const;
};
diff --git a/core/cubic_defs.h b/core/cubic_defs.h
index 33751c97..f3ded415 100644
--- a/core/cubic_defs.h
+++ b/core/cubic_defs.h
@@ -1,13 +1,15 @@
#ifndef CORE_CUBIC_DEFS_H
#define CORE_CUBIC_DEFS_H
+#include <array>
+
/* The number of distinct phase intervals within the cubic filter tables. */
constexpr unsigned int CubicPhaseBits{5};
constexpr unsigned int CubicPhaseCount{1 << CubicPhaseBits};
struct CubicCoefficients {
- float mCoeffs[4];
- float mDeltas[4];
+ std::array<float,4> mCoeffs;
+ std::array<float,4> mDeltas;
};
#endif /* CORE_CUBIC_DEFS_H */
diff --git a/core/cubic_tables.cpp b/core/cubic_tables.cpp
index 5e7aafad..84462893 100644
--- a/core/cubic_tables.cpp
+++ b/core/cubic_tables.cpp
@@ -2,7 +2,7 @@
#include "cubic_tables.h"
#include <array>
-#include <stddef.h>
+#include <cstddef>
#include "cubic_defs.h"
@@ -41,7 +41,7 @@ struct SplineFilterArray {
mTable[pi].mDeltas[3] = -mTable[pi].mCoeffs[3];
}
- constexpr auto& getTable() const noexcept { return mTable; }
+ [[nodiscard]] constexpr auto& getTable() const noexcept { return mTable; }
};
constexpr SplineFilterArray SplineFilter{};
diff --git a/core/dbus_wrap.cpp b/core/dbus_wrap.cpp
index 48419566..05d9fc06 100644
--- a/core/dbus_wrap.cpp
+++ b/core/dbus_wrap.cpp
@@ -8,16 +8,22 @@
#include <mutex>
#include <type_traits>
-#include "albit.h"
#include "logging.h"
void PrepareDBus()
{
- static constexpr char libname[] = "libdbus-1.so.3";
+ const char *libname{"libdbus-1.so.3"};
+
+ dbus_handle = LoadLib(libname);
+ if(!dbus_handle)
+ {
+ WARN("Failed to load %s\n", libname);
+ return;
+ }
auto load_func = [](auto &f, const char *name) -> void
- { f = al::bit_cast<std::remove_reference_t<decltype(f)>>(GetSymbol(dbus_handle, name)); };
+ { f = reinterpret_cast<std::remove_reference_t<decltype(f)>>(GetSymbol(dbus_handle, name)); };
#define LOAD_FUNC(x) do { \
load_func(p##x, #x); \
if(!p##x) \
@@ -29,14 +35,8 @@ void PrepareDBus()
} \
} while(0);
- dbus_handle = LoadLib(libname);
- if(!dbus_handle)
- {
- WARN("Failed to load %s\n", libname);
- return;
- }
+ DBUS_FUNCTIONS(LOAD_FUNC)
-DBUS_FUNCTIONS(LOAD_FUNC)
#undef LOAD_FUNC
}
#endif
diff --git a/core/devformat.h b/core/devformat.h
index 485826a3..d918e531 100644
--- a/core/devformat.h
+++ b/core/devformat.h
@@ -2,6 +2,7 @@
#define CORE_DEVFORMAT_H
#include <cstdint>
+#include <cstddef>
using uint = unsigned int;
@@ -71,7 +72,7 @@ enum DevFmtChannels : unsigned char {
DevFmtChannelsDefault = DevFmtStereo
};
-#define MAX_OUTPUT_CHANNELS 16
+inline constexpr size_t MaxOutputChannels{16};
/* DevFmtType traits, providing the type, etc given a DevFmtType. */
template<DevFmtType T>
diff --git a/core/device.cpp b/core/device.cpp
index 2766c5e4..795a9601 100644
--- a/core/device.cpp
+++ b/core/device.cpp
@@ -9,15 +9,12 @@
#include "mastering.h"
-al::FlexArray<ContextBase*> DeviceBase::sEmptyContextArray{0u};
+static_assert(std::atomic<std::chrono::nanoseconds>::is_always_lock_free);
-DeviceBase::DeviceBase(DeviceType type) : Type{type}, mContexts{&sEmptyContextArray}
+DeviceBase::DeviceBase(DeviceType type)
+ : Type{type}, mContexts{al::FlexArray<ContextBase*>::Create(0)}
{
}
-DeviceBase::~DeviceBase()
-{
- auto *oldarray = mContexts.exchange(nullptr, std::memory_order_relaxed);
- if(oldarray != &sEmptyContextArray) delete oldarray;
-}
+DeviceBase::~DeviceBase() = default;
diff --git a/core/device.h b/core/device.h
index b1ffc9ce..1da08727 100644
--- a/core/device.h
+++ b/core/device.h
@@ -17,6 +17,7 @@
#include "bufferline.h"
#include "devformat.h"
#include "filters/nfc.h"
+#include "flexarray.h"
#include "intrusive_ptr.h"
#include "mixer/hrtfdefs.h"
#include "opthelpers.h"
@@ -25,8 +26,10 @@
#include "vector.h"
class BFormatDec;
+namespace Bs2b {
struct bs2b;
-struct Compressor;
+} // namespace Bs2b
+class Compressor;
struct ContextBase;
struct DirectHrtfState;
struct HrtfStore;
@@ -34,12 +37,12 @@ struct HrtfStore;
using uint = unsigned int;
-#define MIN_OUTPUT_RATE 8000
-#define MAX_OUTPUT_RATE 192000
-#define DEFAULT_OUTPUT_RATE 48000
+inline constexpr size_t MinOutputRate{8000};
+inline constexpr size_t MaxOutputRate{192000};
+inline constexpr size_t DefaultOutputRate{48000};
-#define DEFAULT_UPDATE_SIZE 960 /* 20ms */
-#define DEFAULT_NUM_UPDATES 3
+inline constexpr size_t DefaultUpdateSize{960}; /* 20ms */
+inline constexpr size_t DefaultNumUpdates{3};
enum class DeviceType : uint8_t {
@@ -82,7 +85,7 @@ struct DistanceComp {
float *Buffer{nullptr};
};
- std::array<ChanData,MAX_OUTPUT_CHANNELS> mChannels;
+ std::array<ChanData,MaxOutputChannels> mChannels;
al::FlexArray<float,16> mSamples;
DistanceComp(size_t count) : mSamples{count} { }
@@ -158,8 +161,6 @@ enum {
// Specifies if the DSP is paused at user request
DevicePaused,
- // Specifies if the device is currently running
- DeviceRunning,
// Specifies if the output plays directly on/in ears (headphones, headset,
// ear buds, etc).
@@ -173,12 +174,13 @@ enum {
DeviceFlagsCount
};
-struct DeviceBase {
- /* To avoid extraneous allocations, a 0-sized FlexArray<ContextBase*> is
- * defined globally as a sharable object.
- */
- static al::FlexArray<ContextBase*> sEmptyContextArray;
+enum class DeviceState : uint8_t {
+ Unprepared,
+ Configured,
+ Playing
+};
+struct DeviceBase {
std::atomic<bool> Connected{true};
const DeviceType Type{};
@@ -202,6 +204,7 @@ struct DeviceBase {
// Device flags
std::bitset<DeviceFlagsCount> Flags{};
+ DeviceState mDeviceState{DeviceState::Unprepared};
uint NumAuxSends{};
@@ -218,8 +221,8 @@ struct DeviceBase {
*/
NfcFilter mNFCtrlFilter{};
- uint SamplesDone{0u};
- std::chrono::nanoseconds ClockBase{0};
+ std::atomic<uint> mSamplesDone{0u};
+ std::atomic<std::chrono::nanoseconds> mClockBase{std::chrono::nanoseconds{}};
std::chrono::nanoseconds FixedLatency{0};
AmbiRotateMatrix mAmbiRotateMatrix{};
@@ -229,24 +232,24 @@ struct DeviceBase {
static constexpr size_t MixerLineSize{BufferLineSize + DecoderBase::sMaxPadding};
static constexpr size_t MixerChannelsMax{16};
using MixerBufferLine = std::array<float,MixerLineSize>;
- alignas(16) std::array<MixerBufferLine,MixerChannelsMax> mSampleData;
- alignas(16) std::array<float,MixerLineSize+MaxResamplerPadding> mResampleData;
+ alignas(16) std::array<MixerBufferLine,MixerChannelsMax> mSampleData{};
+ alignas(16) std::array<float,MixerLineSize+MaxResamplerPadding> mResampleData{};
- alignas(16) float FilteredData[BufferLineSize];
+ alignas(16) std::array<float,BufferLineSize> FilteredData{};
union {
- alignas(16) float HrtfSourceData[BufferLineSize + HrtfHistoryLength];
- alignas(16) float NfcSampleData[BufferLineSize];
+ alignas(16) std::array<float,BufferLineSize+HrtfHistoryLength> HrtfSourceData{};
+ alignas(16) std::array<float,BufferLineSize> NfcSampleData;
};
/* Persistent storage for HRTF mixing. */
- alignas(16) float2 HrtfAccumData[BufferLineSize + HrirLength];
+ alignas(16) std::array<float2,BufferLineSize+HrirLength> HrtfAccumData{};
/* Mixing buffer used by the Dry mix and Real output. */
al::vector<FloatBufferLine, 16> MixBuffer;
/* The "dry" path corresponds to the main output. */
MixParams Dry;
- uint NumChannelsPerOrder[MaxAmbiOrder+1]{};
+ std::array<uint,MaxAmbiOrder+1> NumChannelsPerOrder{};
/* "Real" output, which will be written to the device buffer. May alias the
* dry buffer.
@@ -265,7 +268,7 @@ struct DeviceBase {
std::unique_ptr<BFormatDec> AmbiDecoder;
/* Stereo-to-binaural filter */
- std::unique_ptr<bs2b> Bs2b;
+ std::unique_ptr<Bs2b::bs2b> Bs2b;
using PostProc = void(DeviceBase::*)(const size_t SamplesToDo);
PostProc PostProcess{nullptr};
@@ -284,10 +287,10 @@ struct DeviceBase {
* the end, so the bottom bit indicates if the device is currently mixing
* and the upper bits indicates how many mixes have been done.
*/
- RefCount MixCount{0u};
+ std::atomic<uint> mMixCount{0u};
// Contexts created on this device
- std::atomic<al::FlexArray<ContextBase*>*> mContexts{nullptr};
+ al::atomic_unique_ptr<al::FlexArray<ContextBase*>> mContexts;
DeviceBase(DeviceType type);
@@ -295,18 +298,56 @@ struct DeviceBase {
DeviceBase& operator=(const DeviceBase&) = delete;
~DeviceBase();
- uint bytesFromFmt() const noexcept { return BytesFromDevFmt(FmtType); }
- uint channelsFromFmt() const noexcept { return ChannelsFromDevFmt(FmtChans, mAmbiOrder); }
- uint frameSizeFromFmt() const noexcept { return bytesFromFmt() * channelsFromFmt(); }
+ [[nodiscard]] auto bytesFromFmt() const noexcept -> uint { return BytesFromDevFmt(FmtType); }
+ [[nodiscard]] auto channelsFromFmt() const noexcept -> uint { return ChannelsFromDevFmt(FmtChans, mAmbiOrder); }
+ [[nodiscard]] auto frameSizeFromFmt() const noexcept -> uint { return bytesFromFmt() * channelsFromFmt(); }
+
+ struct MixLock {
+ std::atomic<uint> &mCount;
+ const uint mLastVal;
+
+ MixLock(std::atomic<uint> &count, const uint last_val) noexcept
+ : mCount{count}, mLastVal{last_val}
+ { }
+ /* Increment the mix count when the lock goes out of scope to "release"
+ * it (lsb should be 0).
+ */
+ ~MixLock() { mCount.store(mLastVal+2, std::memory_order_release); }
+ };
+ auto getWriteMixLock() noexcept
+ {
+ /* Increment the mix count at the start of mixing and writing clock
+ * info (lsb should be 1).
+ */
+ const auto mixCount = mMixCount.load(std::memory_order_relaxed);
+ mMixCount.store(mixCount+1, std::memory_order_relaxed);
+ std::atomic_thread_fence(std::memory_order_release);
+ return MixLock{mMixCount, mixCount};
+ }
- uint waitForMix() const noexcept
+ /** Waits for the mixer to not be mixing or updating the clock. */
+ [[nodiscard]] auto waitForMix() const noexcept -> uint
{
uint refcount;
- while((refcount=MixCount.load(std::memory_order_acquire))&1) {
+ while((refcount=mMixCount.load(std::memory_order_acquire))&1) {
}
return refcount;
}
+ /**
+ * Helper to get the current clock time from the device's ClockBase, and
+ * SamplesDone converted from the sample rate. Should only be called while
+ * watching the MixCount.
+ */
+ [[nodiscard]] auto getClockTime() const noexcept -> std::chrono::nanoseconds
+ {
+ using std::chrono::seconds;
+ using std::chrono::nanoseconds;
+
+ auto ns = nanoseconds{seconds{mSamplesDone.load(std::memory_order_relaxed)}} / Frequency;
+ return mClockBase.load(std::memory_order_relaxed) + ns;
+ }
+
void ProcessHrtf(const size_t SamplesToDo);
void ProcessAmbiDec(const size_t SamplesToDo);
void ProcessAmbiDecStablized(const size_t SamplesToDo);
@@ -320,8 +361,8 @@ struct DeviceBase {
void renderSamples(void *outBuffer, const uint numSamples, const size_t frameStep);
/* Caller must lock the device state, and the mixer must not be running. */
-#ifdef __USE_MINGW_ANSI_STDIO
- [[gnu::format(gnu_printf,2,3)]]
+#ifdef __MINGW32__
+ [[gnu::format(__MINGW_PRINTF_FORMAT,2,3)]]
#else
[[gnu::format(printf,2,3)]]
#endif
@@ -331,11 +372,9 @@ struct DeviceBase {
* Returns the index for the given channel name (e.g. FrontCenter), or
* InvalidChannelIndex if it doesn't exist.
*/
- uint8_t channelIdxByName(Channel chan) const noexcept
+ [[nodiscard]] auto channelIdxByName(Channel chan) const noexcept -> uint8_t
{ return RealOut.ChannelIndex[chan]; }
- DISABLE_ALLOC()
-
private:
uint renderSamples(const uint numSamples);
};
diff --git a/core/effects/base.h b/core/effects/base.h
index 83df7cf0..df4eb129 100644
--- a/core/effects/base.h
+++ b/core/effects/base.h
@@ -2,7 +2,8 @@
#define CORE_EFFECTS_BASE_H
#include <array>
-#include <stddef.h>
+#include <cstddef>
+#include <variant>
#include "almalloc.h"
#include "alspan.h"
@@ -19,21 +20,21 @@ struct RealMixParams;
/** Target gain for the reverb decay feedback reaching the decay time. */
-constexpr float ReverbDecayGain{0.001f}; /* -60 dB */
+inline constexpr float ReverbDecayGain{0.001f}; /* -60 dB */
-constexpr float ReverbMaxReflectionsDelay{0.3f};
-constexpr float ReverbMaxLateReverbDelay{0.1f};
+inline constexpr float ReverbMaxReflectionsDelay{0.3f};
+inline constexpr float ReverbMaxLateReverbDelay{0.1f};
enum class ChorusWaveform {
Sinusoid,
Triangle
};
-constexpr float ChorusMaxDelay{0.016f};
-constexpr float FlangerMaxDelay{0.004f};
+inline constexpr float ChorusMaxDelay{0.016f};
+inline constexpr float FlangerMaxDelay{0.004f};
-constexpr float EchoMaxDelay{0.207f};
-constexpr float EchoMaxLRDelay{0.404f};
+inline constexpr float EchoMaxDelay{0.207f};
+inline constexpr float EchoMaxLRDelay{0.404f};
enum class FShifterDirection {
Down,
@@ -59,120 +60,148 @@ enum class VMorpherWaveform {
Sawtooth
};
-union EffectProps {
- struct {
- float Density;
- float Diffusion;
- float Gain;
- float GainHF;
- float GainLF;
- float DecayTime;
- float DecayHFRatio;
- float DecayLFRatio;
- float ReflectionsGain;
- float ReflectionsDelay;
- float ReflectionsPan[3];
- float LateReverbGain;
- float LateReverbDelay;
- float LateReverbPan[3];
- float EchoTime;
- float EchoDepth;
- float ModulationTime;
- float ModulationDepth;
- float AirAbsorptionGainHF;
- float HFReference;
- float LFReference;
- float RoomRolloffFactor;
- bool DecayHFLimit;
- } Reverb;
-
- struct {
- float AttackTime;
- float ReleaseTime;
- float Resonance;
- float PeakGain;
- } Autowah;
-
- struct {
- ChorusWaveform Waveform;
- int Phase;
- float Rate;
- float Depth;
- float Feedback;
- float Delay;
- } Chorus; /* Also Flanger */
-
- struct {
- bool OnOff;
- } Compressor;
-
- struct {
- float Edge;
- float Gain;
- float LowpassCutoff;
- float EQCenter;
- float EQBandwidth;
- } Distortion;
-
- struct {
- float Delay;
- float LRDelay;
-
- float Damping;
- float Feedback;
-
- float Spread;
- } Echo;
-
- struct {
- float LowCutoff;
- float LowGain;
- float Mid1Center;
- float Mid1Gain;
- float Mid1Width;
- float Mid2Center;
- float Mid2Gain;
- float Mid2Width;
- float HighCutoff;
- float HighGain;
- } Equalizer;
-
- struct {
- float Frequency;
- FShifterDirection LeftDirection;
- FShifterDirection RightDirection;
- } Fshifter;
-
- struct {
- float Frequency;
- float HighPassCutoff;
- ModulatorWaveform Waveform;
- } Modulator;
-
- struct {
- int CoarseTune;
- int FineTune;
- } Pshifter;
-
- struct {
- float Rate;
- VMorpherPhenome PhonemeA;
- VMorpherPhenome PhonemeB;
- int PhonemeACoarseTuning;
- int PhonemeBCoarseTuning;
- VMorpherWaveform Waveform;
- } Vmorpher;
-
- struct {
- float Gain;
- } Dedicated;
-
- struct {
- std::array<float,3> OrientAt;
- std::array<float,3> OrientUp;
- } Convolution;
+struct ReverbProps {
+ float Density;
+ float Diffusion;
+ float Gain;
+ float GainHF;
+ float GainLF;
+ float DecayTime;
+ float DecayHFRatio;
+ float DecayLFRatio;
+ float ReflectionsGain;
+ float ReflectionsDelay;
+ std::array<float,3> ReflectionsPan;
+ float LateReverbGain;
+ float LateReverbDelay;
+ std::array<float,3> LateReverbPan;
+ float EchoTime;
+ float EchoDepth;
+ float ModulationTime;
+ float ModulationDepth;
+ float AirAbsorptionGainHF;
+ float HFReference;
+ float LFReference;
+ float RoomRolloffFactor;
+ bool DecayHFLimit;
};
+struct AutowahProps {
+ float AttackTime;
+ float ReleaseTime;
+ float Resonance;
+ float PeakGain;
+};
+
+struct ChorusProps {
+ ChorusWaveform Waveform;
+ int Phase;
+ float Rate;
+ float Depth;
+ float Feedback;
+ float Delay;
+};
+
+struct FlangerProps {
+ ChorusWaveform Waveform;
+ int Phase;
+ float Rate;
+ float Depth;
+ float Feedback;
+ float Delay;
+};
+
+struct CompressorProps {
+ bool OnOff;
+};
+
+struct DistortionProps {
+ float Edge;
+ float Gain;
+ float LowpassCutoff;
+ float EQCenter;
+ float EQBandwidth;
+};
+
+struct EchoProps {
+ float Delay;
+ float LRDelay;
+
+ float Damping;
+ float Feedback;
+
+ float Spread;
+};
+
+struct EqualizerProps {
+ float LowCutoff;
+ float LowGain;
+ float Mid1Center;
+ float Mid1Gain;
+ float Mid1Width;
+ float Mid2Center;
+ float Mid2Gain;
+ float Mid2Width;
+ float HighCutoff;
+ float HighGain;
+};
+
+struct FshifterProps {
+ float Frequency;
+ FShifterDirection LeftDirection;
+ FShifterDirection RightDirection;
+};
+
+struct ModulatorProps {
+ float Frequency;
+ float HighPassCutoff;
+ ModulatorWaveform Waveform;
+};
+
+struct PshifterProps {
+ int CoarseTune;
+ int FineTune;
+};
+
+struct VmorpherProps {
+ float Rate;
+ VMorpherPhenome PhonemeA;
+ VMorpherPhenome PhonemeB;
+ int PhonemeACoarseTuning;
+ int PhonemeBCoarseTuning;
+ VMorpherWaveform Waveform;
+};
+
+struct DedicatedDialogProps {
+ float Gain;
+};
+
+struct DedicatedLfeProps {
+ float Gain;
+};
+
+struct ConvolutionProps {
+ std::array<float,3> OrientAt;
+ std::array<float,3> OrientUp;
+};
+
+using EffectProps = std::variant<std::monostate,
+ ReverbProps,
+ AutowahProps,
+ ChorusProps,
+ FlangerProps,
+ CompressorProps,
+ DistortionProps,
+ EchoProps,
+ EqualizerProps,
+ FshifterProps,
+ ModulatorProps,
+ PshifterProps,
+ VmorpherProps,
+ DedicatedDialogProps,
+ DedicatedLfeProps,
+ ConvolutionProps>;
+
struct EffectTarget {
MixParams *Main;
diff --git a/core/effectslot.cpp b/core/effectslot.cpp
index db8aa078..6c80317e 100644
--- a/core/effectslot.cpp
+++ b/core/effectslot.cpp
@@ -3,7 +3,7 @@
#include "effectslot.h"
-#include <stddef.h>
+#include <cstddef>
#include "almalloc.h"
#include "context.h"
@@ -14,6 +14,8 @@ EffectSlotArray *EffectSlot::CreatePtrArray(size_t count) noexcept
/* Allocate space for twice as many pointers, so the mixer has scratch
* space to store a sorted list during mixing.
*/
- void *ptr{al_calloc(alignof(EffectSlotArray), EffectSlotArray::Sizeof(count*2))};
- return al::construct_at(static_cast<EffectSlotArray*>(ptr), count);
+ static constexpr auto AlignVal = std::align_val_t{alignof(EffectSlotArray)};
+ if(gsl::owner<void*> ptr{::operator new[](EffectSlotArray::Sizeof(count*2), AlignVal)})
+ return al::construct_at(static_cast<EffectSlotArray*>(ptr), count);
+ return nullptr;
}
diff --git a/core/effectslot.h b/core/effectslot.h
index 2624ae5f..cf8503ff 100644
--- a/core/effectslot.h
+++ b/core/effectslot.h
@@ -6,6 +6,7 @@
#include "almalloc.h"
#include "device.h"
#include "effects/base.h"
+#include "flexarray.h"
#include "intrusive_ptr.h"
struct EffectSlot;
@@ -45,8 +46,6 @@ struct EffectSlotProps {
al::intrusive_ptr<EffectState> State;
std::atomic<EffectSlotProps*> next;
-
- DEF_NEWDEL(EffectSlotProps)
};
@@ -82,8 +81,6 @@ struct EffectSlot {
static EffectSlotArray *CreatePtrArray(size_t count) noexcept;
-
- DEF_NEWDEL(EffectSlot)
};
#endif /* CORE_EFFECTSLOT_H */
diff --git a/core/except.cpp b/core/except.cpp
index 45fd4eb5..86c7ccca 100644
--- a/core/except.cpp
+++ b/core/except.cpp
@@ -21,7 +21,7 @@ void base_exception::setMessage(const char* msg, std::va_list args)
if(msglen > 0) LIKELY
{
mMessage.resize(static_cast<size_t>(msglen)+1);
- std::vsnprintf(const_cast<char*>(mMessage.data()), mMessage.length(), msg, args2);
+ std::vsnprintf(mMessage.data(), mMessage.length(), msg, args2);
mMessage.pop_back();
}
va_end(args2);
diff --git a/core/except.h b/core/except.h
index 0e28e9df..90e3346e 100644
--- a/core/except.h
+++ b/core/except.h
@@ -14,12 +14,13 @@ class base_exception : public std::exception {
protected:
base_exception() = default;
- virtual ~base_exception();
- void setMessage(const char *msg, std::va_list args);
+ auto setMessage(const char *msg, std::va_list args) -> void;
public:
- const char *what() const noexcept override { return mMessage.c_str(); }
+ ~base_exception() override;
+
+ [[nodiscard]] auto what() const noexcept -> const char* override { return mMessage.c_str(); }
};
} // namespace al
diff --git a/core/filters/biquad.cpp b/core/filters/biquad.cpp
index a0a62eb8..6671f60f 100644
--- a/core/filters/biquad.cpp
+++ b/core/filters/biquad.cpp
@@ -27,8 +27,8 @@ void BiquadFilterR<Real>::setParams(BiquadType type, Real f0norm, Real gain, Rea
const Real alpha{sin_w0/2.0f * rcpQ};
Real sqrtgain_alpha_2;
- Real a[3]{ 1.0f, 0.0f, 0.0f };
- Real b[3]{ 1.0f, 0.0f, 0.0f };
+ std::array<Real,3> a{{1.0f, 0.0f, 0.0f}};
+ std::array<Real,3> b{{1.0f, 0.0f, 0.0f}};
/* Calculate filter coefficients depending on filter type */
switch(type)
diff --git a/core/filters/biquad.h b/core/filters/biquad.h
index 75a4009b..e176caae 100644
--- a/core/filters/biquad.h
+++ b/core/filters/biquad.h
@@ -119,9 +119,9 @@ public:
void dualProcess(BiquadFilterR &other, const al::span<const Real> src, Real *dst);
/* Rather hacky. It's just here to support "manual" processing. */
- std::pair<Real,Real> getComponents() const noexcept { return {mZ1, mZ2}; }
+ [[nodiscard]] auto getComponents() const noexcept -> std::pair<Real,Real> { return {mZ1, mZ2}; }
void setComponents(Real z1, Real z2) noexcept { mZ1 = z1; mZ2 = z2; }
- Real processOne(const Real in, Real &z1, Real &z2) const noexcept
+ [[nodiscard]] auto processOne(const Real in, Real &z1, Real &z2) const noexcept -> Real
{
const Real out{in*mB0 + z1};
z1 = in*mB1 - out*mA1 + z2;
diff --git a/core/filters/nfc.cpp b/core/filters/nfc.cpp
index aa64c613..95b84e2c 100644
--- a/core/filters/nfc.cpp
+++ b/core/filters/nfc.cpp
@@ -48,12 +48,12 @@
namespace {
-constexpr float B[5][4] = {
- { 0.0f },
- { 1.0f },
- { 3.0f, 3.0f },
- { 3.6778f, 6.4595f, 2.3222f },
- { 4.2076f, 11.4877f, 5.7924f, 9.1401f }
+constexpr std::array B{
+ std::array{ 0.0f, 0.0f, 0.0f, 0.0f},
+ std::array{ 1.0f, 0.0f, 0.0f, 0.0f},
+ std::array{ 3.0f, 3.0f, 0.0f, 0.0f},
+ std::array{3.6778f, 6.4595f, 2.3222f, 0.0f},
+ std::array{4.2076f, 11.4877f, 5.7924f, 9.1401f}
};
NfcFilter1 NfcFilterCreate1(const float w0, const float w1) noexcept
diff --git a/core/filters/nfc.h b/core/filters/nfc.h
index 4b8e68b5..9c58f863 100644
--- a/core/filters/nfc.h
+++ b/core/filters/nfc.h
@@ -1,30 +1,31 @@
#ifndef CORE_FILTERS_NFC_H
#define CORE_FILTERS_NFC_H
+#include <array>
#include <cstddef>
#include "alspan.h"
struct NfcFilter1 {
- float base_gain, gain;
- float b1, a1;
- float z[1];
+ float base_gain{1.0f}, gain{1.0f};
+ float b1{}, a1{};
+ std::array<float,1> z{};
};
struct NfcFilter2 {
- float base_gain, gain;
- float b1, b2, a1, a2;
- float z[2];
+ float base_gain{1.0f}, gain{1.0f};
+ float b1{}, b2{}, a1{}, a2{};
+ std::array<float,2> z{};
};
struct NfcFilter3 {
- float base_gain, gain;
- float b1, b2, b3, a1, a2, a3;
- float z[3];
+ float base_gain{1.0f}, gain{1.0f};
+ float b1{}, b2{}, b3{}, a1{}, a2{}, a3{};
+ std::array<float,3> z{};
};
struct NfcFilter4 {
- float base_gain, gain;
- float b1, b2, b3, b4, a1, a2, a3, a4;
- float z[4];
+ float base_gain{1.0f}, gain{1.0f};
+ float b1{}, b2{}, b3{}, b4{}, a1{}, a2{}, a3{}, a4{};
+ std::array<float,4> z{};
};
class NfcFilter {
diff --git a/core/fmt_traits.cpp b/core/fmt_traits.cpp
index 054d8766..9d79287d 100644
--- a/core/fmt_traits.cpp
+++ b/core/fmt_traits.cpp
@@ -6,7 +6,7 @@
namespace al {
-const int16_t muLawDecompressionTable[256] = {
+const std::array<int16_t,256> muLawDecompressionTable{{
-32124,-31100,-30076,-29052,-28028,-27004,-25980,-24956,
-23932,-22908,-21884,-20860,-19836,-18812,-17788,-16764,
-15996,-15484,-14972,-14460,-13948,-13436,-12924,-12412,
@@ -39,9 +39,9 @@ const int16_t muLawDecompressionTable[256] = {
244, 228, 212, 196, 180, 164, 148, 132,
120, 112, 104, 96, 88, 80, 72, 64,
56, 48, 40, 32, 24, 16, 8, 0
-};
+}};
-const int16_t aLawDecompressionTable[256] = {
+const std::array<int16_t,256> aLawDecompressionTable{{
-5504, -5248, -6016, -5760, -4480, -4224, -4992, -4736,
-7552, -7296, -8064, -7808, -6528, -6272, -7040, -6784,
-2752, -2624, -3008, -2880, -2240, -2112, -2496, -2368,
@@ -74,6 +74,6 @@ const int16_t aLawDecompressionTable[256] = {
1888, 1824, 2016, 1952, 1632, 1568, 1760, 1696,
688, 656, 752, 720, 560, 528, 624, 592,
944, 912, 1008, 976, 816, 784, 880, 848
-};
+}};
} // namespace al
diff --git a/core/fmt_traits.h b/core/fmt_traits.h
index 02473014..101e20b6 100644
--- a/core/fmt_traits.h
+++ b/core/fmt_traits.h
@@ -1,6 +1,7 @@
#ifndef CORE_FMT_TRAITS_H
#define CORE_FMT_TRAITS_H
+#include <array>
#include <cstddef>
#include <stdint.h>
@@ -9,8 +10,8 @@
namespace al {
-extern const int16_t muLawDecompressionTable[256];
-extern const int16_t aLawDecompressionTable[256];
+extern const std::array<int16_t,256> muLawDecompressionTable;
+extern const std::array<int16_t,256> aLawDecompressionTable;
template<FmtType T>
diff --git a/core/fpu_ctrl.cpp b/core/fpu_ctrl.cpp
index 435855ad..28e60c04 100644
--- a/core/fpu_ctrl.cpp
+++ b/core/fpu_ctrl.cpp
@@ -64,29 +64,24 @@ void reset_fpu(unsigned int state [[maybe_unused]])
} // namespace
-void FPUCtl::enter() noexcept
+unsigned int FPUCtl::Set() noexcept
{
- if(this->in_mode) return;
-
+ unsigned int state{};
#if defined(HAVE_SSE_INTRINSICS)
- disable_denormals(&this->sse_state);
+ disable_denormals(&state);
#elif defined(HAVE_SSE)
if((CPUCapFlags&CPU_CAP_SSE))
- disable_denormals(&this->sse_state);
+ disable_denormals(&state);
#endif
-
- this->in_mode = true;
+ return state;
}
-void FPUCtl::leave() noexcept
+void FPUCtl::Reset(unsigned int state [[maybe_unused]]) noexcept
{
- if(!this->in_mode) return;
-
#if defined(HAVE_SSE_INTRINSICS)
- reset_fpu(this->sse_state);
+ reset_fpu(state);
#elif defined(HAVE_SSE)
if((CPUCapFlags&CPU_CAP_SSE))
- reset_fpu(this->sse_state);
+ reset_fpu(state);
#endif
- this->in_mode = false;
}
diff --git a/core/fpu_ctrl.h b/core/fpu_ctrl.h
index 9554313a..d4f75ec3 100644
--- a/core/fpu_ctrl.h
+++ b/core/fpu_ctrl.h
@@ -2,20 +2,31 @@
#define CORE_FPU_CTRL_H
class FPUCtl {
-#if defined(HAVE_SSE_INTRINSICS) || (defined(__GNUC__) && defined(HAVE_SSE))
unsigned int sse_state{};
-#endif
bool in_mode{};
+ static unsigned int Set() noexcept;
+ static void Reset(unsigned int state) noexcept;
+
public:
- FPUCtl() noexcept { enter(); in_mode = true; }
- ~FPUCtl() { if(in_mode) leave(); }
+ FPUCtl() noexcept : sse_state{Set()}, in_mode{true} { }
+ ~FPUCtl() { if(in_mode) Reset(sse_state); }
FPUCtl(const FPUCtl&) = delete;
FPUCtl& operator=(const FPUCtl&) = delete;
- void enter() noexcept;
- void leave() noexcept;
+ void enter() noexcept
+ {
+ if(!in_mode)
+ sse_state = Set();
+ in_mode = true;
+ }
+ void leave() noexcept
+ {
+ if(in_mode)
+ Reset(sse_state);
+ in_mode = false;
+ }
};
#endif /* CORE_FPU_CTRL_H */
diff --git a/core/front_stablizer.h b/core/front_stablizer.h
index 6825111a..8eeb6d74 100644
--- a/core/front_stablizer.h
+++ b/core/front_stablizer.h
@@ -7,6 +7,7 @@
#include "almalloc.h"
#include "bufferline.h"
#include "filters/splitter.h"
+#include "flexarray.h"
struct FrontStablizer {
diff --git a/core/helpers.cpp b/core/helpers.cpp
index 5a996eee..b669b8d6 100644
--- a/core/helpers.cpp
+++ b/core/helpers.cpp
@@ -177,7 +177,7 @@ std::vector<std::string> SearchDataFiles(const char *ext, const char *subdir)
return results;
}
-void SetRTPriority(void)
+void SetRTPriority()
{
#if !defined(ALSOFT_UWP)
if(RTPrioLevel > 0)
@@ -256,7 +256,7 @@ const PathNamePair &GetProcBinary()
#ifndef __SWITCH__
if(pathname.empty())
{
- const char *SelfLinkNames[]{
+ std::array SelfLinkNames{
"/proc/self/exe",
"/proc/self/file",
"/proc/curproc/exe",
diff --git a/core/helpers.h b/core/helpers.h
index df51c116..64fc67fb 100644
--- a/core/helpers.h
+++ b/core/helpers.h
@@ -15,11 +15,11 @@ struct PathNamePair {
: path{std::forward<T>(path_)}, fname{std::forward<U>(fname_)}
{ }
};
-const PathNamePair &GetProcBinary(void);
+const PathNamePair &GetProcBinary();
extern int RTPrioLevel;
extern bool AllowRTTimeLimit;
-void SetRTPriority(void);
+void SetRTPriority();
std::vector<std::string> SearchDataFiles(const char *match, const char *subdir);
diff --git a/core/hrtf.cpp b/core/hrtf.cpp
index 9a13a004..eef68bf9 100644
--- a/core/hrtf.cpp
+++ b/core/hrtf.cpp
@@ -18,6 +18,7 @@
#include <mutex>
#include <numeric>
#include <optional>
+#include <tuple>
#include <type_traits>
#include <utility>
#include <vector>
@@ -88,10 +89,12 @@ constexpr uint HrirDelayFracHalf{HrirDelayFracOne >> 1};
static_assert(MaxHrirDelay*HrirDelayFracOne < 256, "MAX_HRIR_DELAY or DELAY_FRAC too large");
+/* NOLINTBEGIN(*-avoid-c-arrays) */
constexpr char magicMarker00[8]{'M','i','n','P','H','R','0','0'};
constexpr char magicMarker01[8]{'M','i','n','P','H','R','0','1'};
constexpr char magicMarker02[8]{'M','i','n','P','H','R','0','2'};
constexpr char magicMarker03[8]{'M','i','n','P','H','R','0','3'};
+/* NOLINTEND(*-avoid-c-arrays) */
/* First value for pass-through coefficients (remaining are 0), used for omni-
* directional sounds. */
@@ -231,29 +234,29 @@ void HrtfStore::getCoeffs(float elevation, float azimuth, float distance, float
const auto az1 = CalcAzIndex(mElev[ebase + elev1_idx].azCount, azimuth);
/* Calculate the HRIR indices to blend. */
- const size_t idx[4]{
+ const std::array<size_t,4> idx{{
ir0offset + az0.idx,
ir0offset + ((az0.idx+1) % mElev[ebase + elev0.idx].azCount),
ir1offset + az1.idx,
ir1offset + ((az1.idx+1) % mElev[ebase + elev1_idx].azCount)
- };
+ }};
/* Calculate bilinear blending weights, attenuated according to the
* directional panning factor.
*/
- const float blend[4]{
+ const std::array<float,4> blend{{
(1.0f-elev0.blend) * (1.0f-az0.blend) * dirfact,
(1.0f-elev0.blend) * ( az0.blend) * dirfact,
( elev0.blend) * (1.0f-az1.blend) * dirfact,
( elev0.blend) * ( az1.blend) * dirfact
- };
+ }};
/* Calculate the blended HRIR delays. */
- float d{mDelays[idx[0]][0]*blend[0] + mDelays[idx[1]][0]*blend[1] + mDelays[idx[2]][0]*blend[2]
- + mDelays[idx[3]][0]*blend[3]};
+ float d{float(mDelays[idx[0]][0])*blend[0] + float(mDelays[idx[1]][0])*blend[1]
+ + float(mDelays[idx[2]][0])*blend[2] + float(mDelays[idx[3]][0])*blend[3]};
delays[0] = fastf2u(d * float{1.0f/HrirDelayFracOne});
- d = mDelays[idx[0]][1]*blend[0] + mDelays[idx[1]][1]*blend[1] + mDelays[idx[2]][1]*blend[2]
- + mDelays[idx[3]][1]*blend[3];
+ d = float(mDelays[idx[0]][1])*blend[0] + float(mDelays[idx[1]][1])*blend[1]
+ + float(mDelays[idx[2]][1])*blend[2] + float(mDelays[idx[3]][1])*blend[3];
delays[1] = fastf2u(d * float{1.0f/HrirDelayFracOne});
/* Calculate the blended HRIR coefficients. */
@@ -267,7 +270,7 @@ void HrtfStore::getCoeffs(float elevation, float azimuth, float distance, float
const float mult{blend[c]};
auto blend_coeffs = [mult](const float src, const float coeff) noexcept -> float
{ return src*mult + coeff; };
- std::transform(srccoeffs, srccoeffs + HrirLength*2, coeffout, coeffout, blend_coeffs);
+ std::transform(srccoeffs, srccoeffs + HrirLength*2_uz, coeffout, coeffout, blend_coeffs);
}
}
@@ -276,7 +279,8 @@ std::unique_ptr<DirectHrtfState> DirectHrtfState::Create(size_t num_chans)
{ return std::unique_ptr<DirectHrtfState>{new(FamCount(num_chans)) DirectHrtfState{num_chans}}; }
void DirectHrtfState::build(const HrtfStore *Hrtf, const uint irSize, const bool perHrirMin,
- const al::span<const AngularPoint> AmbiPoints, const float (*AmbiMatrix)[MaxAmbiChannels],
+ const al::span<const AngularPoint> AmbiPoints,
+ const al::span<const std::array<float,MaxAmbiChannels>> AmbiMatrix,
const float XOverFreq, const al::span<const float,MaxAmbiOrder+1> AmbiOrderHFGain)
{
using double2 = std::array<double,2>;
@@ -287,7 +291,8 @@ void DirectHrtfState::build(const HrtfStore *Hrtf, const uint irSize, const bool
const double xover_norm{double{XOverFreq} / Hrtf->mSampleRate};
mChannels[0].mSplitter.init(static_cast<float>(xover_norm));
- for(size_t i{0};i < mChannels.size();++i)
+ mChannels[0].mHfScale = AmbiOrderHFGain[0];
+ for(size_t i{1};i < mChannels.size();++i)
{
const size_t order{AmbiIndex::OrderFromChannel[i]};
mChannels[i].mSplitter = mChannels[0].mSplitter;
@@ -307,7 +312,7 @@ void DirectHrtfState::build(const HrtfStore *Hrtf, const uint irSize, const bool
const auto az0 = CalcAzIndex(Hrtf->mElev[elev0.idx].azCount, pt.Azim.value);
const auto az1 = CalcAzIndex(Hrtf->mElev[elev1_idx].azCount, pt.Azim.value);
- const size_t idx[4]{
+ const std::array<size_t,4> idx{
ir0offset + az0.idx,
ir0offset + ((az0.idx+1) % Hrtf->mElev[elev0.idx].azCount),
ir1offset + az1.idx,
@@ -333,34 +338,38 @@ void DirectHrtfState::build(const HrtfStore *Hrtf, const uint irSize, const bool
auto tmpres = std::vector<std::array<double2,HrirLength>>(mChannels.size());
max_delay = 0;
- for(size_t c{0u};c < AmbiPoints.size();++c)
+ auto matrixline = AmbiMatrix.cbegin();
+ for(auto &impulse : impres)
{
- const ConstHrirSpan hrir{impres[c].hrir};
- const uint base_delay{perHrirMin ? minu(impres[c].ldelay, impres[c].rdelay) : min_delay};
- const uint ldelay{hrir_delay_round(impres[c].ldelay - base_delay)};
- const uint rdelay{hrir_delay_round(impres[c].rdelay - base_delay)};
- max_delay = maxu(max_delay, maxu(impres[c].ldelay, impres[c].rdelay) - base_delay);
-
- for(size_t i{0u};i < mChannels.size();++i)
+ const ConstHrirSpan hrir{impulse.hrir};
+ const uint base_delay{perHrirMin ? std::min(impulse.ldelay, impulse.rdelay) : min_delay};
+ const uint ldelay{hrir_delay_round(impulse.ldelay - base_delay)};
+ const uint rdelay{hrir_delay_round(impulse.rdelay - base_delay)};
+ max_delay = std::max(max_delay, std::max(impulse.ldelay, impulse.rdelay) - base_delay);
+
+ auto gains = matrixline->cbegin();
+ ++matrixline;
+ for(auto &result : tmpres)
{
- const double mult{AmbiMatrix[c][i]};
- const size_t numirs{HrirLength - maxz(ldelay, rdelay)};
+ const double mult{*(gains++)};
+ const size_t numirs{HrirLength - std::max(ldelay, rdelay)};
size_t lidx{ldelay}, ridx{rdelay};
for(size_t j{0};j < numirs;++j)
{
- tmpres[i][lidx++][0] += hrir[j][0] * mult;
- tmpres[i][ridx++][1] += hrir[j][1] * mult;
+ result[lidx++][0] += hrir[j][0] * mult;
+ result[ridx++][1] += hrir[j][1] * mult;
}
}
}
impres.clear();
- for(size_t i{0u};i < mChannels.size();++i)
+ auto output = mChannels.begin();
+ for(auto &result : tmpres)
{
- auto copy_arr = [](const double2 &in) noexcept -> float2
+ auto cast_array2 = [](const double2 &in) noexcept -> float2
{ return float2{{static_cast<float>(in[0]), static_cast<float>(in[1])}}; };
- std::transform(tmpres[i].cbegin(), tmpres[i].cend(), mChannels[i].mCoeffs.begin(),
- copy_arr);
+ std::transform(result.cbegin(), result.cend(), output->mCoeffs.begin(), cast_array2);
+ ++output;
}
tmpres.clear();
@@ -378,6 +387,10 @@ std::unique_ptr<HrtfStore> CreateHrtfStore(uint rate, uint8_t irSize,
const al::span<const HrtfStore::Elevation> elevs, const HrirArray *coeffs,
const ubyte2 *delays, const char *filename)
{
+ static_assert(alignof(HrtfStore::Field) <= alignof(HrtfStore));
+ static_assert(alignof(HrtfStore::Elevation) <= alignof(HrtfStore));
+ static_assert(16 <= alignof(HrtfStore));
+
const size_t irCount{size_t{elevs.back().azCount} + elevs.back().irOffset};
size_t total{sizeof(HrtfStore)};
total = RoundUp(total, alignof(HrtfStore::Field)); /* Align for field infos */
@@ -388,11 +401,12 @@ std::unique_ptr<HrtfStore> CreateHrtfStore(uint rate, uint8_t irSize,
total += sizeof(std::declval<HrtfStore&>().mCoeffs[0])*irCount;
total += sizeof(std::declval<HrtfStore&>().mDelays[0])*irCount;
+ static constexpr auto AlignVal = std::align_val_t{alignof(HrtfStore)};
std::unique_ptr<HrtfStore> Hrtf{};
- if(void *ptr{al_calloc(16, total)})
+ if(gsl::owner<void*> ptr{::operator new[](total, AlignVal, std::nothrow)})
{
- Hrtf.reset(al::construct_at(static_cast<HrtfStore*>(ptr)));
- InitRef(Hrtf->mRef, 1u);
+ Hrtf = decltype(Hrtf){::new(ptr) HrtfStore{}};
+ Hrtf->mRef.store(1u, std::memory_order_relaxed);
Hrtf->mSampleRate = rate & 0xff'ff'ff;
Hrtf->mIrSize = irSize;
@@ -492,10 +506,10 @@ T> readle(std::istream &data)
static_assert(num_bits <= sizeof(T)*8, "num_bits is too large for the type");
T ret{};
- std::byte b[sizeof(T)]{};
- if(!data.read(reinterpret_cast<char*>(b), num_bits/8))
+ std::array<std::byte,sizeof(T)> b{};
+ if(!data.read(reinterpret_cast<char*>(b.data()), num_bits/8))
return static_cast<T>(EOF);
- std::reverse_copy(std::begin(b), std::end(b), reinterpret_cast<std::byte*>(&ret));
+ std::reverse_copy(b.begin(), b.end(), reinterpret_cast<std::byte*>(&ret));
return fixsign<num_bits>(ret);
}
@@ -576,7 +590,7 @@ std::unique_ptr<HrtfStore> LoadHrtf00(std::istream &data, const char *filename)
for(auto &hrir : coeffs)
{
for(auto &val : al::span<float2>{hrir.data(), irSize})
- val[0] = readle<int16_t>(data) / 32768.0f;
+ val[0] = float(readle<int16_t>(data)) / 32768.0f;
}
for(auto &val : delays)
val[0] = readle<uint8_t>(data);
@@ -598,9 +612,9 @@ std::unique_ptr<HrtfStore> LoadHrtf00(std::istream &data, const char *filename)
/* Mirror the left ear responses to the right ear. */
MirrorLeftHrirs({elevs.data(), elevs.size()}, coeffs.data(), delays.data());
- const HrtfStore::Field field[1]{{0.0f, evCount}};
- return CreateHrtfStore(rate, static_cast<uint8_t>(irSize), field, {elevs.data(), elevs.size()},
- coeffs.data(), delays.data(), filename);
+ const std::array field{HrtfStore::Field{0.0f, evCount}};
+ return CreateHrtfStore(rate, static_cast<uint8_t>(irSize), field, elevs, coeffs.data(),
+ delays.data(), filename);
}
std::unique_ptr<HrtfStore> LoadHrtf01(std::istream &data, const char *filename)
@@ -654,7 +668,7 @@ std::unique_ptr<HrtfStore> LoadHrtf01(std::istream &data, const char *filename)
for(auto &hrir : coeffs)
{
for(auto &val : al::span<float2>{hrir.data(), irSize})
- val[0] = readle<int16_t>(data) / 32768.0f;
+ val[0] = float(readle<int16_t>(data)) / 32768.0f;
}
for(auto &val : delays)
val[0] = readle<uint8_t>(data);
@@ -676,9 +690,8 @@ std::unique_ptr<HrtfStore> LoadHrtf01(std::istream &data, const char *filename)
/* Mirror the left ear responses to the right ear. */
MirrorLeftHrirs({elevs.data(), elevs.size()}, coeffs.data(), delays.data());
- const HrtfStore::Field field[1]{{0.0f, evCount}};
- return CreateHrtfStore(rate, irSize, field, {elevs.data(), elevs.size()}, coeffs.data(),
- delays.data(), filename);
+ const std::array field{HrtfStore::Field{0.0f, evCount}};
+ return CreateHrtfStore(rate, irSize, field, elevs, coeffs.data(), delays.data(), filename);
}
std::unique_ptr<HrtfStore> LoadHrtf02(std::istream &data, const char *filename)
@@ -747,7 +760,7 @@ std::unique_ptr<HrtfStore> LoadHrtf02(std::istream &data, const char *filename)
return nullptr;
}
- fields[f].distance = distance / 1000.0f;
+ fields[f].distance = float(distance) / 1000.0f;
fields[f].evCount = evCount;
if(f > 0 && fields[f].distance <= fields[f-1].distance)
{
@@ -796,7 +809,7 @@ std::unique_ptr<HrtfStore> LoadHrtf02(std::istream &data, const char *filename)
for(auto &hrir : coeffs)
{
for(auto &val : al::span<float2>{hrir.data(), irSize})
- val[0] = readle<int16_t>(data) / 32768.0f;
+ val[0] = float(readle<int16_t>(data)) / 32768.0f;
}
}
else if(sampleType == SampleType_S24)
@@ -835,8 +848,8 @@ std::unique_ptr<HrtfStore> LoadHrtf02(std::istream &data, const char *filename)
{
for(auto &val : al::span<float2>{hrir.data(), irSize})
{
- val[0] = readle<int16_t>(data) / 32768.0f;
- val[1] = readle<int16_t>(data) / 32768.0f;
+ val[0] = float(readle<int16_t>(data)) / 32768.0f;
+ val[1] = float(readle<int16_t>(data)) / 32768.0f;
}
}
}
@@ -901,7 +914,7 @@ std::unique_ptr<HrtfStore> LoadHrtf02(std::istream &data, const char *filename)
elevs__end = std::copy_backward(elevs_src, elevs_src+field.evCount, elevs__end);
return ebase + field.evCount;
};
- (void)std::accumulate(fields.cbegin(), fields.cend(), ptrdiff_t{0}, copy_azs);
+ std::ignore = std::accumulate(fields.cbegin(), fields.cend(), ptrdiff_t{0}, copy_azs);
assert(elevs_.begin() == elevs__end);
/* Reestablish the IR offset for each elevation index, given the new
@@ -936,7 +949,7 @@ std::unique_ptr<HrtfStore> LoadHrtf02(std::istream &data, const char *filename)
return ebase + field.evCount;
};
- (void)std::accumulate(fields.cbegin(), fields.cend(), ptrdiff_t{0}, copy_irs);
+ std::ignore = std::accumulate(fields.cbegin(), fields.cend(), ptrdiff_t{0}, copy_irs);
assert(coeffs_.begin() == coeffs_end);
assert(delays_.begin() == delays_end);
@@ -946,8 +959,7 @@ std::unique_ptr<HrtfStore> LoadHrtf02(std::istream &data, const char *filename)
delays = std::move(delays_);
}
- return CreateHrtfStore(rate, irSize, {fields.data(), fields.size()},
- {elevs.data(), elevs.size()}, coeffs.data(), delays.data(), filename);
+ return CreateHrtfStore(rate, irSize, fields, elevs, coeffs.data(), delays.data(), filename);
}
std::unique_ptr<HrtfStore> LoadHrtf03(std::istream &data, const char *filename)
@@ -1008,7 +1020,7 @@ std::unique_ptr<HrtfStore> LoadHrtf03(std::istream &data, const char *filename)
return nullptr;
}
- fields[f].distance = distance / 1000.0f;
+ fields[f].distance = float(distance) / 1000.0f;
fields[f].evCount = evCount;
if(f > 0 && fields[f].distance > fields[f-1].distance)
{
@@ -1115,8 +1127,7 @@ std::unique_ptr<HrtfStore> LoadHrtf03(std::istream &data, const char *filename)
}
}
- return CreateHrtfStore(rate, irSize, {fields.data(), fields.size()},
- {elevs.data(), elevs.size()}, coeffs.data(), delays.data(), filename);
+ return CreateHrtfStore(rate, irSize, fields, elevs, coeffs.data(), delays.data(), filename);
}
@@ -1206,6 +1217,7 @@ al::span<const char> GetResource(int /*name*/)
#else
+/* NOLINTNEXTLINE(*-avoid-c-arrays) */
constexpr unsigned char hrtf_default[]{
#include "default_hrtf.txt"
};
@@ -1329,32 +1341,32 @@ HrtfStorePtr GetLoadedHrtf(const std::string &name, const uint devrate)
}
std::unique_ptr<HrtfStore> hrtf;
- char magic[sizeof(magicMarker03)];
- stream->read(magic, sizeof(magic));
+ std::array<char,sizeof(magicMarker03)> magic{};
+ stream->read(magic.data(), magic.size());
if(stream->gcount() < static_cast<std::streamsize>(sizeof(magicMarker03)))
ERR("%s data is too short (%zu bytes)\n", name.c_str(), stream->gcount());
- else if(memcmp(magic, magicMarker03, sizeof(magicMarker03)) == 0)
+ else if(memcmp(magic.data(), magicMarker03, sizeof(magicMarker03)) == 0)
{
TRACE("Detected data set format v3\n");
hrtf = LoadHrtf03(*stream, name.c_str());
}
- else if(memcmp(magic, magicMarker02, sizeof(magicMarker02)) == 0)
+ else if(memcmp(magic.data(), magicMarker02, sizeof(magicMarker02)) == 0)
{
TRACE("Detected data set format v2\n");
hrtf = LoadHrtf02(*stream, name.c_str());
}
- else if(memcmp(magic, magicMarker01, sizeof(magicMarker01)) == 0)
+ else if(memcmp(magic.data(), magicMarker01, sizeof(magicMarker01)) == 0)
{
TRACE("Detected data set format v1\n");
hrtf = LoadHrtf01(*stream, name.c_str());
}
- else if(memcmp(magic, magicMarker00, sizeof(magicMarker00)) == 0)
+ else if(memcmp(magic.data(), magicMarker00, sizeof(magicMarker00)) == 0)
{
TRACE("Detected data set format v0\n");
hrtf = LoadHrtf00(*stream, name.c_str());
}
else
- ERR("Invalid header in %s: \"%.8s\"\n", name.c_str(), magic);
+ ERR("Invalid header in %s: \"%.8s\"\n", name.c_str(), magic.data());
stream.reset();
if(!hrtf)
@@ -1380,7 +1392,7 @@ HrtfStorePtr GetLoadedHrtf(const std::string &name, const uint devrate)
rs.init(hrtf->mSampleRate, devrate);
for(size_t i{0};i < irCount;++i)
{
- HrirArray &coeffs = const_cast<HrirArray&>(hrtf->mCoeffs[i]);
+ auto &coeffs = const_cast<HrirArray&>(hrtf->mCoeffs[i]);
for(size_t j{0};j < 2;++j)
{
std::transform(coeffs.cbegin(), coeffs.cend(), inout[0].begin(),
@@ -1400,7 +1412,7 @@ HrtfStorePtr GetLoadedHrtf(const std::string &name, const uint devrate)
{
for(size_t j{0};j < 2;++j)
{
- const float new_delay{std::round(hrtf->mDelays[i][j] * rate_scale) /
+ const float new_delay{std::round(float(hrtf->mDelays[i][j]) * rate_scale) /
float{HrirDelayFracOne}};
max_delay = maxf(max_delay, new_delay);
new_delays[i][j] = new_delay;
@@ -1420,7 +1432,7 @@ HrtfStorePtr GetLoadedHrtf(const std::string &name, const uint devrate)
for(size_t i{0};i < irCount;++i)
{
- ubyte2 &delays = const_cast<ubyte2&>(hrtf->mDelays[i]);
+ auto &delays = const_cast<ubyte2&>(hrtf->mDelays[i]);
for(size_t j{0};j < 2;++j)
delays[j] = static_cast<ubyte>(float2int(new_delays[i][j]*delay_scale + 0.5f));
}
@@ -1459,9 +1471,9 @@ void HrtfStore::dec_ref()
auto remove_unused = [](LoadedHrtf &hrtf) -> bool
{
HrtfStore *entry{hrtf.mEntry.get()};
- if(entry && ReadRef(entry->mRef) == 0)
+ if(entry && entry->mRef.load() == 0)
{
- TRACE("Unloading unused HRTF %s\n", hrtf.mFilename.data());
+ TRACE("Unloading unused HRTF %s\n", hrtf.mFilename.c_str());
hrtf.mEntry = nullptr;
return true;
}
diff --git a/core/hrtf.h b/core/hrtf.h
index 5e6e09a8..882724b8 100644
--- a/core/hrtf.h
+++ b/core/hrtf.h
@@ -13,12 +13,13 @@
#include "atomic.h"
#include "ambidefs.h"
#include "bufferline.h"
-#include "mixer/hrtfdefs.h"
+#include "flexarray.h"
#include "intrusive_ptr.h"
+#include "mixer/hrtfdefs.h"
-struct HrtfStore {
- RefCount mRef;
+struct alignas(16) HrtfStore {
+ std::atomic<uint> mRef;
uint mSampleRate : 24;
uint mIrSize : 8;
@@ -46,7 +47,14 @@ struct HrtfStore {
void add_ref();
void dec_ref();
- DEF_PLACE_NEWDEL()
+ void *operator new(size_t) = delete;
+ void *operator new[](size_t) = delete;
+ void operator delete[](void*) noexcept = delete;
+
+ void operator delete(gsl::owner<void*> block, void*) noexcept
+ { ::operator delete[](block, std::align_val_t{alignof(HrtfStore)}); }
+ void operator delete(gsl::owner<void*> block) noexcept
+ { ::operator delete[](block, std::align_val_t{alignof(HrtfStore)}); }
};
using HrtfStorePtr = al::intrusive_ptr<HrtfStore>;
@@ -60,7 +68,7 @@ struct AngularPoint {
struct DirectHrtfState {
- std::array<float,BufferLineSize> mTemp;
+ std::array<float,BufferLineSize> mTemp{};
/* HRTF filter state for dry buffer content */
uint mIrSize{0};
@@ -74,7 +82,8 @@ struct DirectHrtfState {
* are ordered and scaled according to the matrix input.
*/
void build(const HrtfStore *Hrtf, const uint irSize, const bool perHrirMin,
- const al::span<const AngularPoint> AmbiPoints, const float (*AmbiMatrix)[MaxAmbiChannels],
+ const al::span<const AngularPoint> AmbiPoints,
+ const al::span<const std::array<float,MaxAmbiChannels>> AmbiMatrix,
const float XOverFreq, const al::span<const float,MaxAmbiOrder+1> AmbiOrderHFGain);
static std::unique_ptr<DirectHrtfState> Create(size_t num_chans);
diff --git a/core/logging.h b/core/logging.h
index 06b7cdde..a8d9b731 100644
--- a/core/logging.h
+++ b/core/logging.h
@@ -22,8 +22,8 @@ using LogCallbackFunc = void(*)(void *userptr, char level, const char *message,
void al_set_log_callback(LogCallbackFunc callback, void *userptr);
-#ifdef __USE_MINGW_ANSI_STDIO
-[[gnu::format(gnu_printf,2,3)]]
+#ifdef __MINGW32__
+[[gnu::format(__MINGW_PRINTF_FORMAT,2,3)]]
#else
[[gnu::format(printf,2,3)]]
#endif
diff --git a/core/mastering.cpp b/core/mastering.cpp
index 4445719b..9eaabc35 100644
--- a/core/mastering.cpp
+++ b/core/mastering.cpp
@@ -21,8 +21,8 @@
static_assert((BufferLineSize & (BufferLineSize-1)) == 0, "BufferLineSize is not a power of 2");
struct SlidingHold {
- alignas(16) float mValues[BufferLineSize];
- uint mExpiries[BufferLineSize];
+ alignas(16) FloatBufferLine mValues;
+ std::array<uint,BufferLineSize> mExpiries;
uint mLowerIndex;
uint mUpperIndex;
uint mLength;
@@ -44,8 +44,8 @@ float UpdateSlidingHold(SlidingHold *Hold, const uint i, const float in)
{
static constexpr uint mask{BufferLineSize - 1};
const uint length{Hold->mLength};
- float (&values)[BufferLineSize] = Hold->mValues;
- uint (&expiries)[BufferLineSize] = Hold->mExpiries;
+ const al::span values{Hold->mValues};
+ const al::span expiries{Hold->mExpiries};
uint lowerIndex{Hold->mLowerIndex};
uint upperIndex{Hold->mUpperIndex};
@@ -60,14 +60,16 @@ float UpdateSlidingHold(SlidingHold *Hold, const uint i, const float in)
}
else
{
- do {
+ auto findLowerIndex = [&lowerIndex,in,values]() noexcept -> bool
+ {
do {
if(!(in >= values[lowerIndex]))
- goto found_place;
+ return true;
} while(lowerIndex--);
+ return false;
+ };
+ while(!findLowerIndex())
lowerIndex = mask;
- } while(true);
- found_place:
lowerIndex = (lowerIndex + 1) & mask;
values[lowerIndex] = in;
@@ -82,38 +84,38 @@ float UpdateSlidingHold(SlidingHold *Hold, const uint i, const float in)
void ShiftSlidingHold(SlidingHold *Hold, const uint n)
{
- auto exp_begin = std::begin(Hold->mExpiries) + Hold->mUpperIndex;
- auto exp_last = std::begin(Hold->mExpiries) + Hold->mLowerIndex;
- if(exp_last-exp_begin < 0)
+ auto exp_upper = Hold->mExpiries.begin() + Hold->mUpperIndex;
+ if(Hold->mLowerIndex < Hold->mUpperIndex)
{
- std::transform(exp_begin, std::end(Hold->mExpiries), exp_begin,
- [n](uint e){ return e - n; });
- exp_begin = std::begin(Hold->mExpiries);
+ std::transform(exp_upper, Hold->mExpiries.end(), exp_upper,
+ [n](const uint e) noexcept { return e - n; });
+ exp_upper = Hold->mExpiries.begin();
}
- std::transform(exp_begin, exp_last+1, exp_begin, [n](uint e){ return e - n; });
+ const auto exp_lower = Hold->mExpiries.begin() + Hold->mLowerIndex;
+ std::transform(exp_upper, exp_lower+1, exp_upper,
+ [n](const uint e) noexcept { return e - n; });
}
+} // namespace
/* Multichannel compression is linked via the absolute maximum of all
* channels.
*/
-void LinkChannels(Compressor *Comp, const uint SamplesToDo, const FloatBufferLine *OutBuffer)
+void Compressor::linkChannels(const uint SamplesToDo, const FloatBufferLine *OutBuffer)
{
- const size_t numChans{Comp->mNumChans};
-
ASSUME(SamplesToDo > 0);
- ASSUME(numChans > 0);
- auto side_begin = std::begin(Comp->mSideChain) + Comp->mLookAhead;
+ const auto side_begin = mSideChain.begin() + mLookAhead;
std::fill(side_begin, side_begin+SamplesToDo, 0.0f);
auto fill_max = [SamplesToDo,side_begin](const FloatBufferLine &input) -> void
{
const float *RESTRICT buffer{al::assume_aligned<16>(input.data())};
- auto max_abs = std::bind(maxf, _1, std::bind(static_cast<float(&)(float)>(std::fabs), _2));
+ auto max_abs = [](const float s0, const float s1) noexcept -> float
+ { return std::max(s0, std::fabs(s1)); };
std::transform(side_begin, side_begin+SamplesToDo, buffer, side_begin, max_abs);
};
- std::for_each(OutBuffer, OutBuffer+numChans, fill_max);
+ std::for_each(OutBuffer, OutBuffer+mNumChans, fill_max);
}
/* This calculates the squared crest factor of the control signal for the
@@ -121,59 +123,59 @@ void LinkChannels(Compressor *Comp, const uint SamplesToDo, const FloatBufferLin
* it uses an instantaneous squared peak detector and a squared RMS detector
* both with 200ms release times.
*/
-void CrestDetector(Compressor *Comp, const uint SamplesToDo)
+void Compressor::crestDetector(const uint SamplesToDo)
{
- const float a_crest{Comp->mCrestCoeff};
- float y2_peak{Comp->mLastPeakSq};
- float y2_rms{Comp->mLastRmsSq};
+ const float a_crest{mCrestCoeff};
+ float y2_peak{mLastPeakSq};
+ float y2_rms{mLastRmsSq};
ASSUME(SamplesToDo > 0);
auto calc_crest = [&y2_rms,&y2_peak,a_crest](const float x_abs) noexcept -> float
{
- const float x2{clampf(x_abs * x_abs, 0.000001f, 1000000.0f)};
+ const float x2{clampf(x_abs*x_abs, 0.000001f, 1000000.0f)};
- y2_peak = maxf(x2, lerpf(x2, y2_peak, a_crest));
+ y2_peak = std::max(x2, lerpf(x2, y2_peak, a_crest));
y2_rms = lerpf(x2, y2_rms, a_crest);
return y2_peak / y2_rms;
};
- auto side_begin = std::begin(Comp->mSideChain) + Comp->mLookAhead;
- std::transform(side_begin, side_begin+SamplesToDo, std::begin(Comp->mCrestFactor), calc_crest);
+ const auto side_begin = mSideChain.begin() + mLookAhead;
+ std::transform(side_begin, side_begin+SamplesToDo, mCrestFactor.begin(), calc_crest);
- Comp->mLastPeakSq = y2_peak;
- Comp->mLastRmsSq = y2_rms;
+ mLastPeakSq = y2_peak;
+ mLastRmsSq = y2_rms;
}
/* The side-chain starts with a simple peak detector (based on the absolute
* value of the incoming signal) and performs most of its operations in the
* log domain.
*/
-void PeakDetector(Compressor *Comp, const uint SamplesToDo)
+void Compressor::peakDetector(const uint SamplesToDo)
{
ASSUME(SamplesToDo > 0);
- /* Clamp the minimum amplitude to near-zero and convert to logarithm. */
- auto side_begin = std::begin(Comp->mSideChain) + Comp->mLookAhead;
+ /* Clamp the minimum amplitude to near-zero and convert to logarithmic. */
+ const auto side_begin = mSideChain.begin() + mLookAhead;
std::transform(side_begin, side_begin+SamplesToDo, side_begin,
- [](float s) { return std::log(maxf(0.000001f, s)); });
+ [](float s) { return std::log(std::max(0.000001f, s)); });
}
/* An optional hold can be used to extend the peak detector so it can more
* solidly detect fast transients. This is best used when operating as a
* limiter.
*/
-void PeakHoldDetector(Compressor *Comp, const uint SamplesToDo)
+void Compressor::peakHoldDetector(const uint SamplesToDo)
{
ASSUME(SamplesToDo > 0);
- SlidingHold *hold{Comp->mHold};
+ SlidingHold *hold{mHold.get()};
uint i{0};
auto detect_peak = [&i,hold](const float x_abs) -> float
{
- const float x_G{std::log(maxf(0.000001f, x_abs))};
+ const float x_G{std::log(std::max(0.000001f, x_abs))};
return UpdateSlidingHold(hold, i++, x_G);
};
- auto side_begin = std::begin(Comp->mSideChain) + Comp->mLookAhead;
+ auto side_begin = mSideChain.begin() + mLookAhead;
std::transform(side_begin, side_begin+SamplesToDo, side_begin, detect_peak);
ShiftSlidingHold(hold, SamplesToDo);
@@ -184,46 +186,46 @@ void PeakHoldDetector(Compressor *Comp, const uint SamplesToDo)
* to knee width, attack/release times, make-up/post gain, and clipping
* reduction.
*/
-void GainCompressor(Compressor *Comp, const uint SamplesToDo)
+void Compressor::gainCompressor(const uint SamplesToDo)
{
- const bool autoKnee{Comp->mAuto.Knee};
- const bool autoAttack{Comp->mAuto.Attack};
- const bool autoRelease{Comp->mAuto.Release};
- const bool autoPostGain{Comp->mAuto.PostGain};
- const bool autoDeclip{Comp->mAuto.Declip};
- const uint lookAhead{Comp->mLookAhead};
- const float threshold{Comp->mThreshold};
- const float slope{Comp->mSlope};
- const float attack{Comp->mAttack};
- const float release{Comp->mRelease};
- const float c_est{Comp->mGainEstimate};
- const float a_adp{Comp->mAdaptCoeff};
- const float *crestFactor{Comp->mCrestFactor};
- float postGain{Comp->mPostGain};
- float knee{Comp->mKnee};
+ const bool autoKnee{mAuto.Knee};
+ const bool autoAttack{mAuto.Attack};
+ const bool autoRelease{mAuto.Release};
+ const bool autoPostGain{mAuto.PostGain};
+ const bool autoDeclip{mAuto.Declip};
+ const float threshold{mThreshold};
+ const float slope{mSlope};
+ const float attack{mAttack};
+ const float release{mRelease};
+ const float c_est{mGainEstimate};
+ const float a_adp{mAdaptCoeff};
+ auto lookAhead = mSideChain.cbegin() + mLookAhead;
+ auto crestFactor = mCrestFactor.cbegin();
+ float postGain{mPostGain};
+ float knee{mKnee};
float t_att{attack};
float t_rel{release - attack};
float a_att{std::exp(-1.0f / t_att)};
float a_rel{std::exp(-1.0f / t_rel)};
- float y_1{Comp->mLastRelease};
- float y_L{Comp->mLastAttack};
- float c_dev{Comp->mLastGainDev};
+ float y_1{mLastRelease};
+ float y_L{mLastAttack};
+ float c_dev{mLastGainDev};
ASSUME(SamplesToDo > 0);
- for(float &sideChain : al::span<float>{Comp->mSideChain, SamplesToDo})
+ auto process = [&](const float input) -> float
{
if(autoKnee)
- knee = maxf(0.0f, 2.5f * (c_dev + c_est));
+ knee = std::max(0.0f, 2.5f * (c_dev + c_est));
const float knee_h{0.5f * knee};
/* This is the gain computer. It applies a static compression curve
* to the control signal.
*/
- const float x_over{std::addressof(sideChain)[lookAhead] - threshold};
+ const float x_over{*(lookAhead++) - threshold};
const float y_G{
(x_over <= -knee_h) ? 0.0f :
- (std::fabs(x_over) < knee_h) ? (x_over + knee_h) * (x_over + knee_h) / (2.0f * knee) :
+ (std::fabs(x_over) < knee_h) ? (x_over+knee_h) * (x_over+knee_h) / (2.0f * knee) :
x_over};
const float y2_crest{*(crestFactor++)};
@@ -243,7 +245,7 @@ void GainCompressor(Compressor *Comp, const uint SamplesToDo)
* above to compensate for the chained operating mode.
*/
const float x_L{-slope * y_G};
- y_1 = maxf(x_L, lerpf(x_L, y_1, a_rel));
+ y_1 = std::max(x_L, lerpf(x_L, y_1, a_rel));
y_L = lerpf(y_1, y_L, a_att);
/* Knee width and make-up gain automation make use of a smoothed
@@ -262,17 +264,19 @@ void GainCompressor(Compressor *Comp, const uint SamplesToDo)
* same output level.
*/
if(autoDeclip)
- c_dev = maxf(c_dev, sideChain - y_L - threshold - c_est);
+ c_dev = std::max(c_dev, input - y_L - threshold - c_est);
postGain = -(c_dev + c_est);
}
- sideChain = std::exp(postGain - y_L);
- }
+ return std::exp(postGain - y_L);
+ };
+ auto sideChain = al::span{mSideChain}.first(SamplesToDo);
+ std::transform(sideChain.begin(), sideChain.end(), sideChain.begin(), process);
- Comp->mLastRelease = y_1;
- Comp->mLastAttack = y_L;
- Comp->mLastGainDev = c_dev;
+ mLastRelease = y_1;
+ mLastAttack = y_L;
+ mLastGainDev = c_dev;
}
/* Combined with the hold time, a look-ahead delay can improve handling of
@@ -280,10 +284,10 @@ void GainCompressor(Compressor *Comp, const uint SamplesToDo)
* reaching the offending impulse. This is best used when operating as a
* limiter.
*/
-void SignalDelay(Compressor *Comp, const uint SamplesToDo, FloatBufferLine *OutBuffer)
+void Compressor::signalDelay(const uint SamplesToDo, FloatBufferLine *OutBuffer)
{
- const size_t numChans{Comp->mNumChans};
- const uint lookAhead{Comp->mLookAhead};
+ const size_t numChans{mNumChans};
+ const uint lookAhead{mLookAhead};
ASSUME(SamplesToDo > 0);
ASSUME(numChans > 0);
@@ -292,7 +296,7 @@ void SignalDelay(Compressor *Comp, const uint SamplesToDo, FloatBufferLine *OutB
for(size_t c{0};c < numChans;c++)
{
float *inout{al::assume_aligned<16>(OutBuffer[c].data())};
- float *delaybuf{al::assume_aligned<16>(Comp->mDelay[c].data())};
+ float *delaybuf{al::assume_aligned<16>(mDelay[c].data())};
auto inout_end = inout + SamplesToDo;
if(SamplesToDo >= lookAhead) LIKELY
@@ -308,8 +312,6 @@ void SignalDelay(Compressor *Comp, const uint SamplesToDo, FloatBufferLine *OutB
}
}
-} // namespace
-
std::unique_ptr<Compressor> Compressor::Create(const size_t NumChans, const float SampleRate,
const bool AutoKnee, const bool AutoAttack, const bool AutoRelease, const bool AutoPostGain,
@@ -317,24 +319,12 @@ std::unique_ptr<Compressor> Compressor::Create(const size_t NumChans, const floa
const float PostGainDb, const float ThresholdDb, const float Ratio, const float KneeDb,
const float AttackTime, const float ReleaseTime)
{
- const auto lookAhead = static_cast<uint>(
- clampf(std::round(LookAheadTime*SampleRate), 0.0f, BufferLineSize-1));
- const auto hold = static_cast<uint>(
- clampf(std::round(HoldTime*SampleRate), 0.0f, BufferLineSize-1));
+ const auto lookAhead = static_cast<uint>(clampf(std::round(LookAheadTime*SampleRate), 0.0f,
+ BufferLineSize-1));
+ const auto hold = static_cast<uint>(clampf(std::round(HoldTime*SampleRate), 0.0f,
+ BufferLineSize-1));
- size_t size{sizeof(Compressor)};
- if(lookAhead > 0)
- {
- size += sizeof(*Compressor::mDelay) * NumChans;
- /* The sliding hold implementation doesn't handle a length of 1. A 1-
- * sample hold is useless anyway, it would only ever give back what was
- * just given to it.
- */
- if(hold > 1)
- size += sizeof(*Compressor::mHold);
- }
-
- auto Comp = CompressorPtr{al::construct_at(static_cast<Compressor*>(al_calloc(16, size)))};
+ auto Comp = CompressorPtr{new Compressor{}};
Comp->mNumChans = NumChans;
Comp->mAuto.Knee = AutoKnee;
Comp->mAuto.Attack = AutoAttack;
@@ -343,12 +333,12 @@ std::unique_ptr<Compressor> Compressor::Create(const size_t NumChans, const floa
Comp->mAuto.Declip = AutoPostGain && AutoDeclip;
Comp->mLookAhead = lookAhead;
Comp->mPreGain = std::pow(10.0f, PreGainDb / 20.0f);
- Comp->mPostGain = PostGainDb * std::log(10.0f) / 20.0f;
- Comp->mThreshold = ThresholdDb * std::log(10.0f) / 20.0f;
- Comp->mSlope = 1.0f / maxf(1.0f, Ratio) - 1.0f;
- Comp->mKnee = maxf(0.0f, KneeDb * std::log(10.0f) / 20.0f);
- Comp->mAttack = maxf(1.0f, AttackTime * SampleRate);
- Comp->mRelease = maxf(1.0f, ReleaseTime * SampleRate);
+ Comp->mPostGain = std::log(10.0f)/20.0f * PostGainDb;
+ Comp->mThreshold = std::log(10.0f)/20.0f * ThresholdDb;
+ Comp->mSlope = 1.0f / std::max(1.0f, Ratio) - 1.0f;
+ Comp->mKnee = std::max(0.0f, std::log(10.0f)/20.0f * KneeDb);
+ Comp->mAttack = std::max(1.0f, AttackTime * SampleRate);
+ Comp->mRelease = std::max(1.0f, ReleaseTime * SampleRate);
/* Knee width automation actually treats the compressor as a limiter. By
* varying the knee width, it can effectively be seen as applying
@@ -359,17 +349,18 @@ std::unique_ptr<Compressor> Compressor::Create(const size_t NumChans, const floa
if(lookAhead > 0)
{
+ /* The sliding hold implementation doesn't handle a length of 1. A 1-
+ * sample hold is useless anyway, it would only ever give back what was
+ * just given to it.
+ */
if(hold > 1)
{
- Comp->mHold = al::construct_at(reinterpret_cast<SlidingHold*>(Comp.get() + 1));
+ Comp->mHold = std::make_unique<SlidingHold>();
Comp->mHold->mValues[0] = -std::numeric_limits<float>::infinity();
Comp->mHold->mExpiries[0] = hold;
Comp->mHold->mLength = hold;
- Comp->mDelay = reinterpret_cast<FloatBufferLine*>(Comp->mHold + 1);
}
- else
- Comp->mDelay = reinterpret_cast<FloatBufferLine*>(Comp.get() + 1);
- std::uninitialized_fill_n(Comp->mDelay, NumChans, FloatBufferLine{});
+ Comp->mDelay.resize(NumChans, FloatBufferLine{});
}
Comp->mCrestCoeff = std::exp(-1.0f / (0.200f * SampleRate)); // 200ms
@@ -379,15 +370,7 @@ std::unique_ptr<Compressor> Compressor::Create(const size_t NumChans, const floa
return Comp;
}
-Compressor::~Compressor()
-{
- if(mHold)
- std::destroy_at(mHold);
- mHold = nullptr;
- if(mDelay)
- std::destroy_n(mDelay, mNumChans);
- mDelay = nullptr;
-}
+Compressor::~Compressor() = default;
void Compressor::process(const uint SamplesToDo, FloatBufferLine *OutBuffer)
@@ -404,36 +387,36 @@ void Compressor::process(const uint SamplesToDo, FloatBufferLine *OutBuffer)
{
float *buffer{al::assume_aligned<16>(input.data())};
std::transform(buffer, buffer+SamplesToDo, buffer,
- [preGain](float s) { return s * preGain; });
+ [preGain](const float s) noexcept { return s * preGain; });
};
std::for_each(OutBuffer, OutBuffer+numChans, apply_gain);
}
- LinkChannels(this, SamplesToDo, OutBuffer);
+ linkChannels(SamplesToDo, OutBuffer);
if(mAuto.Attack || mAuto.Release)
- CrestDetector(this, SamplesToDo);
+ crestDetector(SamplesToDo);
if(mHold)
- PeakHoldDetector(this, SamplesToDo);
+ peakHoldDetector(SamplesToDo);
else
- PeakDetector(this, SamplesToDo);
+ peakDetector(SamplesToDo);
- GainCompressor(this, SamplesToDo);
+ gainCompressor(SamplesToDo);
- if(mDelay)
- SignalDelay(this, SamplesToDo, OutBuffer);
+ if(!mDelay.empty())
+ signalDelay(SamplesToDo, OutBuffer);
- const float (&sideChain)[BufferLineSize*2] = mSideChain;
- auto apply_comp = [SamplesToDo,&sideChain](FloatBufferLine &input) noexcept -> void
+ const auto sideChain = al::span{mSideChain};
+ auto apply_comp = [SamplesToDo,sideChain](FloatBufferLine &input) noexcept -> void
{
float *buffer{al::assume_aligned<16>(input.data())};
- const float *gains{al::assume_aligned<16>(&sideChain[0])};
+ const float *gains{al::assume_aligned<16>(sideChain.data())};
std::transform(gains, gains+SamplesToDo, buffer, buffer,
- [](float g, float s) { return g * s; });
+ [](const float g, const float s) noexcept { return g * s; });
};
std::for_each(OutBuffer, OutBuffer+numChans, apply_comp);
- auto side_begin = std::begin(mSideChain) + SamplesToDo;
- std::copy(side_begin, side_begin+mLookAhead, std::begin(mSideChain));
+ auto side_begin = mSideChain.begin() + SamplesToDo;
+ std::copy(side_begin, side_begin+mLookAhead, mSideChain.begin());
}
diff --git a/core/mastering.h b/core/mastering.h
index 1a36937c..ca7266a3 100644
--- a/core/mastering.h
+++ b/core/mastering.h
@@ -1,10 +1,14 @@
#ifndef CORE_MASTERING_H
#define CORE_MASTERING_H
+#include <array>
#include <memory>
#include "almalloc.h"
+#include "alnumeric.h"
+#include "alspan.h"
#include "bufferline.h"
+#include "vector.h"
struct SlidingHold;
@@ -21,7 +25,7 @@ using uint = unsigned int;
*
* http://c4dm.eecs.qmul.ac.uk/audioengineering/compressors/
*/
-struct Compressor {
+class Compressor {
size_t mNumChans{0u};
struct {
@@ -44,11 +48,11 @@ struct Compressor {
float mAttack{0.0f};
float mRelease{0.0f};
- alignas(16) float mSideChain[2*BufferLineSize]{};
- alignas(16) float mCrestFactor[BufferLineSize]{};
+ alignas(16) std::array<float,BufferLineSize*2_uz> mSideChain{};
+ alignas(16) std::array<float,BufferLineSize> mCrestFactor{};
- SlidingHold *mHold{nullptr};
- FloatBufferLine *mDelay{nullptr};
+ std::unique_ptr<SlidingHold> mHold;
+ al::vector<FloatBufferLine,16> mDelay;
float mCrestCoeff{0.0f};
float mGainEstimate{0.0f};
@@ -60,12 +64,19 @@ struct Compressor {
float mLastAttack{0.0f};
float mLastGainDev{0.0f};
+ Compressor() = default;
+ void linkChannels(const uint SamplesToDo, const FloatBufferLine *OutBuffer);
+ void crestDetector(const uint SamplesToDo);
+ void peakDetector(const uint SamplesToDo);
+ void peakHoldDetector(const uint SamplesToDo);
+ void gainCompressor(const uint SamplesToDo);
+ void signalDelay(const uint SamplesToDo, FloatBufferLine *OutBuffer);
+
+public:
~Compressor();
void process(const uint SamplesToDo, FloatBufferLine *OutBuffer);
- int getLookAhead() const noexcept { return static_cast<int>(mLookAhead); }
-
- DEF_PLACE_NEWDEL()
+ [[nodiscard]] auto getLookAhead() const noexcept -> uint { return mLookAhead; }
/**
* The compressor is initialized with the following settings:
diff --git a/core/mixer/defs.h b/core/mixer/defs.h
index 48daca9b..4d0d19bf 100644
--- a/core/mixer/defs.h
+++ b/core/mixer/defs.h
@@ -2,7 +2,8 @@
#define CORE_MIXER_DEFS_H
#include <array>
-#include <stdlib.h>
+#include <cstdlib>
+#include <variant>
#include "alspan.h"
#include "core/bufferline.h"
@@ -17,12 +18,12 @@ using uint = unsigned int;
using float2 = std::array<float,2>;
-constexpr int MixerFracBits{16};
-constexpr int MixerFracOne{1 << MixerFracBits};
-constexpr int MixerFracMask{MixerFracOne - 1};
-constexpr int MixerFracHalf{MixerFracOne >> 1};
+inline constexpr int MixerFracBits{16};
+inline constexpr int MixerFracOne{1 << MixerFracBits};
+inline constexpr int MixerFracMask{MixerFracOne - 1};
+inline constexpr int MixerFracHalf{MixerFracOne >> 1};
-constexpr float GainSilenceThreshold{0.00001f}; /* -100dB */
+inline constexpr float GainSilenceThreshold{0.00001f}; /* -100dB */
enum class Resampler : uint8_t {
@@ -59,10 +60,7 @@ struct CubicState {
const CubicCoefficients *filter;
};
-union InterpState {
- CubicState cubic;
- BsincState bsinc;
-};
+using InterpState = std::variant<CubicState,BsincState>;
using ResamplerFunc = void(*)(const InterpState *state, const float *RESTRICT src, uint frac,
const uint increment, const al::span<float> dst);
@@ -94,7 +92,8 @@ void MixDirectHrtf_(const FloatBufferSpan LeftOut, const FloatBufferSpan RightOu
/* Vectorized resampler helpers */
template<size_t N>
-inline void InitPosArrays(uint frac, uint increment, uint (&frac_arr)[N], uint (&pos_arr)[N])
+inline void InitPosArrays(uint frac, uint increment, const al::span<uint,N> frac_arr,
+ const al::span<uint,N> pos_arr)
{
pos_arr[0] = 0;
frac_arr[0] = frac;
diff --git a/core/mixer/mixer_c.cpp b/core/mixer/mixer_c.cpp
index 28a92ef7..93306bba 100644
--- a/core/mixer/mixer_c.cpp
+++ b/core/mixer/mixer_c.cpp
@@ -28,53 +28,53 @@ constexpr uint CubicPhaseDiffBits{MixerFracBits - CubicPhaseBits};
constexpr uint CubicPhaseDiffOne{1 << CubicPhaseDiffBits};
constexpr uint CubicPhaseDiffMask{CubicPhaseDiffOne - 1u};
-inline float do_point(const InterpState&, const float *RESTRICT vals, const uint)
+inline float do_point(const float *RESTRICT vals, const uint)
{ return vals[0]; }
-inline float do_lerp(const InterpState&, const float *RESTRICT vals, const uint frac)
+inline float do_lerp(const float *RESTRICT vals, const uint frac)
{ return lerpf(vals[0], vals[1], static_cast<float>(frac)*(1.0f/MixerFracOne)); }
-inline float do_cubic(const InterpState &istate, const float *RESTRICT vals, const uint frac)
+inline float do_cubic(const CubicState &istate, const float *RESTRICT vals, const uint frac)
{
/* Calculate the phase index and factor. */
const uint pi{frac >> CubicPhaseDiffBits};
const float pf{static_cast<float>(frac&CubicPhaseDiffMask) * (1.0f/CubicPhaseDiffOne)};
- const float *RESTRICT fil{al::assume_aligned<16>(istate.cubic.filter[pi].mCoeffs)};
- const float *RESTRICT phd{al::assume_aligned<16>(istate.cubic.filter[pi].mDeltas)};
+ const float *RESTRICT fil{al::assume_aligned<16>(istate.filter[pi].mCoeffs.data())};
+ const float *RESTRICT phd{al::assume_aligned<16>(istate.filter[pi].mDeltas.data())};
/* Apply the phase interpolated filter. */
return (fil[0] + pf*phd[0])*vals[0] + (fil[1] + pf*phd[1])*vals[1]
+ (fil[2] + pf*phd[2])*vals[2] + (fil[3] + pf*phd[3])*vals[3];
}
-inline float do_bsinc(const InterpState &istate, const float *RESTRICT vals, const uint frac)
+inline float do_bsinc(const BsincState &istate, const float *RESTRICT vals, const uint frac)
{
- const size_t m{istate.bsinc.m};
+ const size_t m{istate.m};
ASSUME(m > 0);
/* Calculate the phase index and factor. */
const uint pi{frac >> BsincPhaseDiffBits};
const float pf{static_cast<float>(frac&BsincPhaseDiffMask) * (1.0f/BsincPhaseDiffOne)};
- const float *RESTRICT fil{istate.bsinc.filter + m*pi*2};
+ const float *RESTRICT fil{istate.filter + m*pi*2_uz};
const float *RESTRICT phd{fil + m};
- const float *RESTRICT scd{fil + BSincPhaseCount*2*m};
+ const float *RESTRICT scd{fil + BSincPhaseCount*2_uz*m};
const float *RESTRICT spd{scd + m};
/* Apply the scale and phase interpolated filter. */
float r{0.0f};
for(size_t j_f{0};j_f < m;j_f++)
- r += (fil[j_f] + istate.bsinc.sf*scd[j_f] + pf*(phd[j_f] + istate.bsinc.sf*spd[j_f])) * vals[j_f];
+ r += (fil[j_f] + istate.sf*scd[j_f] + pf*(phd[j_f] + istate.sf*spd[j_f])) * vals[j_f];
return r;
}
-inline float do_fastbsinc(const InterpState &istate, const float *RESTRICT vals, const uint frac)
+inline float do_fastbsinc(const BsincState &istate, const float *RESTRICT vals, const uint frac)
{
- const size_t m{istate.bsinc.m};
+ const size_t m{istate.m};
ASSUME(m > 0);
/* Calculate the phase index and factor. */
const uint pi{frac >> BsincPhaseDiffBits};
const float pf{static_cast<float>(frac&BsincPhaseDiffMask) * (1.0f/BsincPhaseDiffOne)};
- const float *RESTRICT fil{istate.bsinc.filter + m*pi*2};
+ const float *RESTRICT fil{istate.filter + m*pi*2_uz};
const float *RESTRICT phd{fil + m};
/* Apply the phase interpolated filter. */
@@ -84,16 +84,30 @@ inline float do_fastbsinc(const InterpState &istate, const float *RESTRICT vals,
return r;
}
-using SamplerT = float(&)(const InterpState&, const float*RESTRICT, const uint);
+using SamplerT = float(&)(const float*RESTRICT, const uint);
template<SamplerT Sampler>
-void DoResample(const InterpState *state, const float *RESTRICT src, uint frac,
+void DoResample(const float *RESTRICT src, uint frac, const uint increment,
+ const al::span<float> dst)
+{
+ ASSUME(frac < MixerFracOne);
+ for(float &out : dst)
+ {
+ out = Sampler(src, frac);
+
+ frac += increment;
+ src += frac>>MixerFracBits;
+ frac &= MixerFracMask;
+ }
+}
+
+template<typename T, typename U>
+void DoResample(T sampler, const U istate, const float *RESTRICT src, uint frac,
const uint increment, const al::span<float> dst)
{
- const InterpState istate{*state};
ASSUME(frac < MixerFracOne);
for(float &out : dst)
{
- out = Sampler(istate, src, frac);
+ out = sampler(istate, src, frac);
frac += increment;
src += frac>>MixerFracBits;
@@ -146,29 +160,35 @@ force_inline void MixLine(const al::span<const float> InSamples, float *RESTRICT
} // namespace
template<>
-void Resample_<PointTag,CTag>(const InterpState *state, const float *RESTRICT src, uint frac,
+void Resample_<PointTag,CTag>(const InterpState*, const float *RESTRICT src, uint frac,
const uint increment, const al::span<float> dst)
-{ DoResample<do_point>(state, src, frac, increment, dst); }
+{ DoResample<do_point>(src, frac, increment, dst); }
template<>
-void Resample_<LerpTag,CTag>(const InterpState *state, const float *RESTRICT src, uint frac,
+void Resample_<LerpTag,CTag>(const InterpState*, const float *RESTRICT src, uint frac,
const uint increment, const al::span<float> dst)
-{ DoResample<do_lerp>(state, src, frac, increment, dst); }
+{ DoResample<do_lerp>(src, frac, increment, dst); }
template<>
void Resample_<CubicTag,CTag>(const InterpState *state, const float *RESTRICT src, uint frac,
const uint increment, const al::span<float> dst)
-{ DoResample<do_cubic>(state, src-1, frac, increment, dst); }
+{ DoResample(do_cubic, std::get<CubicState>(*state), src-1, frac, increment, dst); }
template<>
void Resample_<BSincTag,CTag>(const InterpState *state, const float *RESTRICT src, uint frac,
const uint increment, const al::span<float> dst)
-{ DoResample<do_bsinc>(state, src-state->bsinc.l, frac, increment, dst); }
+{
+ const auto istate = std::get<BsincState>(*state);
+ DoResample(do_bsinc, istate, src-istate.l, frac, increment, dst);
+}
template<>
void Resample_<FastBSincTag,CTag>(const InterpState *state, const float *RESTRICT src, uint frac,
const uint increment, const al::span<float> dst)
-{ DoResample<do_fastbsinc>(state, src-state->bsinc.l, frac, increment, dst); }
+{
+ const auto istate = std::get<BsincState>(*state);
+ DoResample(do_fastbsinc, istate, src-istate.l, frac, increment, dst);
+}
template<>
diff --git a/core/mixer/mixer_neon.cpp b/core/mixer/mixer_neon.cpp
index ead775af..9fa2425f 100644
--- a/core/mixer/mixer_neon.cpp
+++ b/core/mixer/mixer_neon.cpp
@@ -146,12 +146,11 @@ void Resample_<LerpTag,NEONTag>(const InterpState*, const float *RESTRICT src, u
const int32x4_t increment4 = vdupq_n_s32(static_cast<int>(increment*4));
const float32x4_t fracOne4 = vdupq_n_f32(1.0f/MixerFracOne);
const int32x4_t fracMask4 = vdupq_n_s32(MixerFracMask);
- alignas(16) uint pos_[4], frac_[4];
- int32x4_t pos4, frac4;
- InitPosArrays(frac, increment, frac_, pos_);
- frac4 = vld1q_s32(reinterpret_cast<int*>(frac_));
- pos4 = vld1q_s32(reinterpret_cast<int*>(pos_));
+ alignas(16) std::array<uint,4> pos_, frac_;
+ InitPosArrays(frac, increment, al::span{frac_}, al::span{pos_});
+ int32x4_t frac4 = vld1q_s32(reinterpret_cast<int*>(frac_.data()));
+ int32x4_t pos4 = vld1q_s32(reinterpret_cast<int*>(pos_.data()));
auto dst_iter = dst.begin();
for(size_t todo{dst.size()>>2};todo;--todo)
@@ -197,7 +196,7 @@ void Resample_<CubicTag,NEONTag>(const InterpState *state, const float *RESTRICT
{
ASSUME(frac < MixerFracOne);
- const CubicCoefficients *RESTRICT filter = al::assume_aligned<16>(state->cubic.filter);
+ const auto *RESTRICT filter = al::assume_aligned<16>(std::get<CubicState>(*state).filter);
src -= 1;
for(float &out_sample : dst)
@@ -209,8 +208,8 @@ void Resample_<CubicTag,NEONTag>(const InterpState *state, const float *RESTRICT
/* Apply the phase interpolated filter. */
/* f = fil + pf*phd */
- const float32x4_t f4 = vmlaq_f32(vld1q_f32(filter[pi].mCoeffs), pf4,
- vld1q_f32(filter[pi].mDeltas));
+ const float32x4_t f4 = vmlaq_f32(vld1q_f32(filter[pi].mCoeffs.data()), pf4,
+ vld1q_f32(filter[pi].mDeltas.data()));
/* r = f*src */
float32x4_t r4{vmulq_f32(f4, vld1q_f32(src))};
@@ -227,13 +226,14 @@ template<>
void Resample_<BSincTag,NEONTag>(const InterpState *state, const float *RESTRICT src, uint frac,
const uint increment, const al::span<float> dst)
{
- const float *const filter{state->bsinc.filter};
- const float32x4_t sf4{vdupq_n_f32(state->bsinc.sf)};
- const size_t m{state->bsinc.m};
+ const auto &bsinc = std::get<BsincState>(*state);
+ const float *const filter{bsinc.filter};
+ const float32x4_t sf4{vdupq_n_f32(bsinc.sf)};
+ const size_t m{bsinc.m};
ASSUME(m > 0);
ASSUME(frac < MixerFracOne);
- src -= state->bsinc.l;
+ src -= bsinc.l;
for(float &out_sample : dst)
{
// Calculate the phase index and factor.
@@ -244,9 +244,9 @@ void Resample_<BSincTag,NEONTag>(const InterpState *state, const float *RESTRICT
float32x4_t r4{vdupq_n_f32(0.0f)};
{
const float32x4_t pf4{vdupq_n_f32(pf)};
- const float *RESTRICT fil{filter + m*pi*2};
+ const float *RESTRICT fil{filter + m*pi*2_uz};
const float *RESTRICT phd{fil + m};
- const float *RESTRICT scd{fil + BSincPhaseCount*2*m};
+ const float *RESTRICT scd{fil + BSincPhaseCount*2_uz*m};
const float *RESTRICT spd{scd + m};
size_t td{m >> 2};
size_t j{0u};
@@ -271,15 +271,16 @@ void Resample_<BSincTag,NEONTag>(const InterpState *state, const float *RESTRICT
}
template<>
-void Resample_<FastBSincTag,NEONTag>(const InterpState *state, const float *RESTRICT src, uint frac,
- const uint increment, const al::span<float> dst)
+void Resample_<FastBSincTag,NEONTag>(const InterpState *state, const float *RESTRICT src,
+ uint frac, const uint increment, const al::span<float> dst)
{
- const float *const filter{state->bsinc.filter};
- const size_t m{state->bsinc.m};
+ const auto &bsinc = std::get<BsincState>(*state);
+ const float *const filter{bsinc.filter};
+ const size_t m{bsinc.m};
ASSUME(m > 0);
ASSUME(frac < MixerFracOne);
- src -= state->bsinc.l;
+ src -= bsinc.l;
for(float &out_sample : dst)
{
// Calculate the phase index and factor.
@@ -290,7 +291,7 @@ void Resample_<FastBSincTag,NEONTag>(const InterpState *state, const float *REST
float32x4_t r4{vdupq_n_f32(0.0f)};
{
const float32x4_t pf4{vdupq_n_f32(pf)};
- const float *RESTRICT fil{filter + m*pi*2};
+ const float *RESTRICT fil{filter + m*pi*2_uz};
const float *RESTRICT phd{fil + m};
size_t td{m >> 2};
size_t j{0u};
diff --git a/core/mixer/mixer_sse.cpp b/core/mixer/mixer_sse.cpp
index 70f77c14..809d585d 100644
--- a/core/mixer/mixer_sse.cpp
+++ b/core/mixer/mixer_sse.cpp
@@ -159,7 +159,7 @@ void Resample_<CubicTag,SSETag>(const InterpState *state, const float *RESTRICT
{
ASSUME(frac < MixerFracOne);
- const CubicCoefficients *RESTRICT filter = al::assume_aligned<16>(state->cubic.filter);
+ const auto *RESTRICT filter = al::assume_aligned<16>(std::get<CubicState>(*state).filter);
src -= 1;
for(float &out_sample : dst)
@@ -171,8 +171,8 @@ void Resample_<CubicTag,SSETag>(const InterpState *state, const float *RESTRICT
/* Apply the phase interpolated filter. */
/* f = fil + pf*phd */
- const __m128 f4 = MLA4(_mm_load_ps(filter[pi].mCoeffs), pf4,
- _mm_load_ps(filter[pi].mDeltas));
+ const __m128 f4 = MLA4(_mm_load_ps(filter[pi].mCoeffs.data()), pf4,
+ _mm_load_ps(filter[pi].mDeltas.data()));
/* r = f*src */
__m128 r4{_mm_mul_ps(f4, _mm_loadu_ps(src))};
@@ -190,13 +190,14 @@ template<>
void Resample_<BSincTag,SSETag>(const InterpState *state, const float *RESTRICT src, uint frac,
const uint increment, const al::span<float> dst)
{
- const float *const filter{state->bsinc.filter};
- const __m128 sf4{_mm_set1_ps(state->bsinc.sf)};
- const size_t m{state->bsinc.m};
+ const auto &bsinc = std::get<BsincState>(*state);
+ const float *const filter{bsinc.filter};
+ const __m128 sf4{_mm_set1_ps(bsinc.sf)};
+ const size_t m{bsinc.m};
ASSUME(m > 0);
ASSUME(frac < MixerFracOne);
- src -= state->bsinc.l;
+ src -= bsinc.l;
for(float &out_sample : dst)
{
// Calculate the phase index and factor.
@@ -207,9 +208,9 @@ void Resample_<BSincTag,SSETag>(const InterpState *state, const float *RESTRICT
__m128 r4{_mm_setzero_ps()};
{
const __m128 pf4{_mm_set1_ps(pf)};
- const float *RESTRICT fil{filter + m*pi*2};
+ const float *RESTRICT fil{filter + m*pi*2_uz};
const float *RESTRICT phd{fil + m};
- const float *RESTRICT scd{fil + BSincPhaseCount*2*m};
+ const float *RESTRICT scd{fil + BSincPhaseCount*2_uz*m};
const float *RESTRICT spd{scd + m};
size_t td{m >> 2};
size_t j{0u};
@@ -238,12 +239,13 @@ template<>
void Resample_<FastBSincTag,SSETag>(const InterpState *state, const float *RESTRICT src, uint frac,
const uint increment, const al::span<float> dst)
{
- const float *const filter{state->bsinc.filter};
- const size_t m{state->bsinc.m};
+ const auto &bsinc = std::get<BsincState>(*state);
+ const float *const filter{bsinc.filter};
+ const size_t m{bsinc.m};
ASSUME(m > 0);
ASSUME(frac < MixerFracOne);
- src -= state->bsinc.l;
+ src -= bsinc.l;
for(float &out_sample : dst)
{
// Calculate the phase index and factor.
@@ -254,7 +256,7 @@ void Resample_<FastBSincTag,SSETag>(const InterpState *state, const float *RESTR
__m128 r4{_mm_setzero_ps()};
{
const __m128 pf4{_mm_set1_ps(pf)};
- const float *RESTRICT fil{filter + m*pi*2};
+ const float *RESTRICT fil{filter + m*pi*2_uz};
const float *RESTRICT phd{fil + m};
size_t td{m >> 2};
size_t j{0u};
diff --git a/core/mixer/mixer_sse2.cpp b/core/mixer/mixer_sse2.cpp
index edaaf7a1..aa08b7ed 100644
--- a/core/mixer/mixer_sse2.cpp
+++ b/core/mixer/mixer_sse2.cpp
@@ -44,8 +44,8 @@ void Resample_<LerpTag,SSE2Tag>(const InterpState*, const float *RESTRICT src, u
const __m128 fracOne4{_mm_set1_ps(1.0f/MixerFracOne)};
const __m128i fracMask4{_mm_set1_epi32(MixerFracMask)};
- alignas(16) uint pos_[4], frac_[4];
- InitPosArrays(frac, increment, frac_, pos_);
+ alignas(16) std::array<uint,4> pos_, frac_;
+ InitPosArrays(frac, increment, al::span{frac_}, al::span{pos_});
__m128i frac4{_mm_setr_epi32(static_cast<int>(frac_[0]), static_cast<int>(frac_[1]),
static_cast<int>(frac_[2]), static_cast<int>(frac_[3]))};
__m128i pos4{_mm_setr_epi32(static_cast<int>(pos_[0]), static_cast<int>(pos_[1]),
diff --git a/core/mixer/mixer_sse41.cpp b/core/mixer/mixer_sse41.cpp
index 8ccd9fd3..d66f9ce5 100644
--- a/core/mixer/mixer_sse41.cpp
+++ b/core/mixer/mixer_sse41.cpp
@@ -45,8 +45,8 @@ void Resample_<LerpTag,SSE4Tag>(const InterpState*, const float *RESTRICT src, u
const __m128 fracOne4{_mm_set1_ps(1.0f/MixerFracOne)};
const __m128i fracMask4{_mm_set1_epi32(MixerFracMask)};
- alignas(16) uint pos_[4], frac_[4];
- InitPosArrays(frac, increment, frac_, pos_);
+ alignas(16) std::array<uint,4> pos_, frac_;
+ InitPosArrays(frac, increment, al::span{frac_}, al::span{pos_});
__m128i frac4{_mm_setr_epi32(static_cast<int>(frac_[0]), static_cast<int>(frac_[1]),
static_cast<int>(frac_[2]), static_cast<int>(frac_[3]))};
__m128i pos4{_mm_setr_epi32(static_cast<int>(pos_[0]), static_cast<int>(pos_[1]),
diff --git a/core/rtkit.cpp b/core/rtkit.cpp
index ff944ebf..73ea132f 100644
--- a/core/rtkit.cpp
+++ b/core/rtkit.cpp
@@ -30,14 +30,14 @@
#include "rtkit.h"
-#include <errno.h>
+#include <cerrno>
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include <memory>
-#include <string.h>
+#include <cstring>
#include <unistd.h>
#include <sys/types.h>
#ifdef __linux__
diff --git a/core/uhjfilter.cpp b/core/uhjfilter.cpp
index 28999e09..681b0abc 100644
--- a/core/uhjfilter.cpp
+++ b/core/uhjfilter.cpp
@@ -5,6 +5,7 @@
#include <algorithm>
#include <iterator>
+#include <vector>
#include "alcomplex.h"
#include "alnumeric.h"
@@ -20,11 +21,6 @@ UhjQualityType UhjEncodeQuality{UhjQualityType::Default};
namespace {
-struct PFFFTSetupDeleter {
- void operator()(PFFFT_Setup *ptr) { pffft_destroy_setup(ptr); }
-};
-using PFFFTSetupPtr = std::unique_ptr<PFFFT_Setup,PFFFTSetupDeleter>;
-
/* Convolution is implemented using a segmented overlap-add method. The filter
* response is broken up into multiple segments of 128 samples, and each
* segment has an FFT applied with a 256-sample buffer (the latter half left
@@ -57,13 +53,11 @@ struct SegmentedFilter {
static_assert(N >= sFftLength);
static_assert((N % sSampleLength) == 0);
- PFFFTSetupPtr mFft;
+ PFFFTSetup mFft;
alignas(16) std::array<float,sFftLength*sNumSegments> mFilterData;
- SegmentedFilter()
+ SegmentedFilter() : mFft{sFftLength, PFFFT_REAL}
{
- mFft = PFFFTSetupPtr{pffft_new_setup(sFftLength, PFFFT_REAL)};
-
using complex_d = std::complex<double>;
constexpr size_t fft_size{N};
constexpr size_t half_size{fft_size / 2};
@@ -71,8 +65,7 @@ struct SegmentedFilter {
/* To set up the filter, we need to generate the desired response.
* Start with a pure delay that passes all frequencies through.
*/
- auto fftBuffer = std::make_unique<complex_d[]>(fft_size);
- std::fill_n(fftBuffer.get(), fft_size, complex_d{});
+ auto fftBuffer = std::vector<complex_d>(fft_size, complex_d{});
fftBuffer[half_size] = 1.0;
/* Convert to the frequency domain, shift the phase of each bin by +90
@@ -82,27 +75,27 @@ struct SegmentedFilter {
* To maintain that and their phase (0 or pi), they're heavily
* attenuated instead of shifted like the others.
*/
- forward_fft(al::span{fftBuffer.get(), fft_size});
+ forward_fft(al::span{fftBuffer});
fftBuffer[0] *= std::numeric_limits<double>::epsilon();
for(size_t i{1};i < half_size;++i)
fftBuffer[i] = complex_d{-fftBuffer[i].imag(), fftBuffer[i].real()};
fftBuffer[half_size] *= std::numeric_limits<double>::epsilon();
for(size_t i{half_size+1};i < fft_size;++i)
fftBuffer[i] = std::conj(fftBuffer[fft_size - i]);
- inverse_fft(al::span{fftBuffer.get(), fft_size});
+ inverse_fft(al::span{fftBuffer});
/* The segments of the filter are converted back to the frequency
* domain, each on their own (0 stuffed).
*/
- auto fftBuffer2 = std::make_unique<complex_d[]>(sFftLength);
+ auto fftBuffer2 = std::vector<complex_d>(sFftLength);
auto fftTmp = al::vector<float,16>(sFftLength);
float *filter{mFilterData.data()};
for(size_t s{0};s < sNumSegments;++s)
{
for(size_t i{0};i < sSampleLength;++i)
fftBuffer2[i] = fftBuffer[sSampleLength*s + i].real() / double{fft_size};
- std::fill_n(fftBuffer2.get()+sSampleLength, sSampleLength, complex_d{});
- forward_fft(al::span{fftBuffer2.get(), sFftLength});
+ std::fill_n(fftBuffer2.data()+sSampleLength, sSampleLength, complex_d{});
+ forward_fft(al::span{fftBuffer2});
/* Convert to zdomain data for PFFFT, scaled by the FFT length so
* the iFFT result will be normalized.
@@ -113,7 +106,7 @@ struct SegmentedFilter {
fftTmp[i*2 + 1] = static_cast<float>((i == 0) ? fftBuffer2[sSampleLength].real()
: fftBuffer2[i].imag()) / float{sFftLength};
}
- pffft_zreorder(mFft.get(), fftTmp.data(), filter, PFFFT_BACKWARD);
+ mFft.zreorder(fftTmp.data(), filter, PFFFT_BACKWARD);
filter += sFftLength;
}
}
@@ -246,7 +239,7 @@ void UhjEncoder<N>::encode(float *LeftOut, float *RightOut,
std::copy_n(mWXInOut.begin(), sSegmentSize, input);
std::fill_n(input+sSegmentSize, sSegmentSize, 0.0f);
- pffft_transform(Filter.mFft.get(), input, input, mWorkData.data(), PFFFT_FORWARD);
+ Filter.mFft.transform(input, input, mWorkData.data(), PFFFT_FORWARD);
/* Convolve each input segment with its IR filter counterpart (aligned
* in time, from newest to oldest).
@@ -255,14 +248,14 @@ void UhjEncoder<N>::encode(float *LeftOut, float *RightOut,
const float *filter{Filter.mFilterData.data()};
for(size_t s{curseg};s < sNumSegments;++s)
{
- pffft_zconvolve_accumulate(Filter.mFft.get(), input, filter, mFftBuffer.data());
+ Filter.mFft.zconvolve_accumulate(input, filter, mFftBuffer.data());
input += sFftLength;
filter += sFftLength;
}
input = mWXHistory.data();
for(size_t s{0};s < curseg;++s)
{
- pffft_zconvolve_accumulate(Filter.mFft.get(), input, filter, mFftBuffer.data());
+ Filter.mFft.zconvolve_accumulate(input, filter, mFftBuffer.data());
input += sFftLength;
filter += sFftLength;
}
@@ -270,8 +263,8 @@ void UhjEncoder<N>::encode(float *LeftOut, float *RightOut,
/* Convert back to samples, writing to the output and storing the extra
* for next time.
*/
- pffft_transform(Filter.mFft.get(), mFftBuffer.data(), mFftBuffer.data(),
- mWorkData.data(), PFFFT_BACKWARD);
+ Filter.mFft.transform(mFftBuffer.data(), mFftBuffer.data(), mWorkData.data(),
+ PFFFT_BACKWARD);
for(size_t i{0};i < sSegmentSize;++i)
mWXInOut[i] = mFftBuffer[i] + mWXInOut[sSegmentSize+i];
diff --git a/core/uhjfilter.h b/core/uhjfilter.h
index 348dc7e1..74ff2167 100644
--- a/core/uhjfilter.h
+++ b/core/uhjfilter.h
@@ -25,7 +25,7 @@ extern UhjQualityType UhjEncodeQuality;
struct UhjAllPassFilter {
struct AllPassState {
/* Last two delayed components for direct form II. */
- float z[2];
+ std::array<float,2> z{};
};
std::array<AllPassState,4> mState;
@@ -110,8 +110,6 @@ struct UhjEncoderIIR final : public UhjEncoderBase {
*/
void encode(float *LeftOut, float *RightOut, const al::span<const float*const,3> InSamples,
const size_t SamplesToDo) override;
-
- DEF_NEWDEL(UhjEncoderIIR)
};
@@ -158,8 +156,6 @@ struct UhjDecoder final : public DecoderBase {
*/
void decode(const al::span<float*> samples, const size_t samplesToDo,
const bool updateState) override;
-
- DEF_NEWDEL(UhjDecoder)
};
struct UhjDecoderIIR final : public DecoderBase {
@@ -184,8 +180,6 @@ struct UhjDecoderIIR final : public DecoderBase {
void decode(const al::span<float*> samples, const size_t samplesToDo,
const bool updateState) override;
-
- DEF_NEWDEL(UhjDecoderIIR)
};
template<size_t N>
@@ -210,8 +204,6 @@ struct UhjStereoDecoder final : public DecoderBase {
*/
void decode(const al::span<float*> samples, const size_t samplesToDo,
const bool updateState) override;
-
- DEF_NEWDEL(UhjStereoDecoder)
};
struct UhjStereoDecoderIIR final : public DecoderBase {
@@ -231,8 +223,6 @@ struct UhjStereoDecoderIIR final : public DecoderBase {
void decode(const al::span<float*> samples, const size_t samplesToDo,
const bool updateState) override;
-
- DEF_NEWDEL(UhjStereoDecoderIIR)
};
#endif /* CORE_UHJFILTER_H */
diff --git a/core/voice.cpp b/core/voice.cpp
index 3889c42d..4a30ee83 100644
--- a/core/voice.cpp
+++ b/core/voice.cpp
@@ -9,11 +9,11 @@
#include <cassert>
#include <climits>
#include <cstdint>
+#include <cstdlib>
#include <iterator>
#include <memory>
#include <new>
#include <optional>
-#include <stdlib.h>
#include <utility>
#include <vector>
@@ -133,18 +133,18 @@ void Voice::InitMixer(std::optional<std::string> resampler)
if(resampler)
{
struct ResamplerEntry {
- const char name[16];
+ const char *name;
const Resampler resampler;
};
- constexpr ResamplerEntry ResamplerList[]{
- { "none", Resampler::Point },
- { "point", Resampler::Point },
- { "linear", Resampler::Linear },
- { "cubic", Resampler::Cubic },
- { "bsinc12", Resampler::BSinc12 },
- { "fast_bsinc12", Resampler::FastBSinc12 },
- { "bsinc24", Resampler::BSinc24 },
- { "fast_bsinc24", Resampler::FastBSinc24 },
+ constexpr std::array ResamplerList{
+ ResamplerEntry{"none", Resampler::Point},
+ ResamplerEntry{"point", Resampler::Point},
+ ResamplerEntry{"linear", Resampler::Linear},
+ ResamplerEntry{"cubic", Resampler::Cubic},
+ ResamplerEntry{"bsinc12", Resampler::BSinc12},
+ ResamplerEntry{"fast_bsinc12", Resampler::FastBSinc12},
+ ResamplerEntry{"bsinc24", Resampler::BSinc24},
+ ResamplerEntry{"fast_bsinc24", Resampler::FastBSinc24},
};
const char *str{resampler->c_str()};
@@ -159,10 +159,10 @@ void Voice::InitMixer(std::optional<std::string> resampler)
str = "cubic";
}
- auto iter = std::find_if(std::begin(ResamplerList), std::end(ResamplerList),
+ auto iter = std::find_if(ResamplerList.begin(), ResamplerList.end(),
[str](const ResamplerEntry &entry) -> bool
{ return al::strcasecmp(str, entry.name) == 0; });
- if(iter == std::end(ResamplerList))
+ if(iter == ResamplerList.end())
ERR("Invalid resampler: %s\n", str);
else
ResamplerDefault = iter->resampler;
@@ -178,7 +178,7 @@ void Voice::InitMixer(std::optional<std::string> resampler)
namespace {
/* IMA ADPCM Stepsize table */
-constexpr int IMAStep_size[89] = {
+constexpr std::array<int,89> IMAStep_size{{
7, 8, 9, 10, 11, 12, 13, 14, 16, 17, 19,
21, 23, 25, 28, 31, 34, 37, 41, 45, 50, 55,
60, 66, 73, 80, 88, 97, 107, 118, 130, 143, 157,
@@ -188,35 +188,35 @@ constexpr int IMAStep_size[89] = {
4026, 4428, 4871, 5358, 5894, 6484, 7132, 7845, 8630, 9493,10442,
11487,12635,13899,15289,16818,18500,20350,22358,24633,27086,29794,
32767
-};
+}};
/* IMA4 ADPCM Codeword decode table */
-constexpr int IMA4Codeword[16] = {
+constexpr std::array<int,16> IMA4Codeword{{
1, 3, 5, 7, 9, 11, 13, 15,
-1,-3,-5,-7,-9,-11,-13,-15,
-};
+}};
/* IMA4 ADPCM Step index adjust decode table */
-constexpr int IMA4Index_adjust[16] = {
+constexpr std::array<int,16>IMA4Index_adjust{{
-1,-1,-1,-1, 2, 4, 6, 8,
-1,-1,-1,-1, 2, 4, 6, 8
-};
+}};
/* MSADPCM Adaption table */
-constexpr int MSADPCMAdaption[16] = {
+constexpr std::array<int,16> MSADPCMAdaption{{
230, 230, 230, 230, 307, 409, 512, 614,
768, 614, 512, 409, 307, 230, 230, 230
-};
+}};
/* MSADPCM Adaption Coefficient tables */
-constexpr int MSADPCMAdaptionCoeff[7][2] = {
- { 256, 0 },
- { 512, -256 },
- { 0, 0 },
- { 192, 64 },
- { 240, 0 },
- { 460, -208 },
- { 392, -232 }
+constexpr std::array MSADPCMAdaptionCoeff{
+ std::array{256, 0},
+ std::array{512, -256},
+ std::array{ 0, 0},
+ std::array{192, 64},
+ std::array{240, 0},
+ std::array{460, -208},
+ std::array{392, -232}
};
@@ -307,7 +307,7 @@ inline void LoadSamples<FmtIMA4>(float *RESTRICT dstSamples, const std::byte *sr
auto decode_sample = [&sample,&index](const uint nibble)
{
- sample += IMA4Codeword[nibble] * IMAStep_size[index] / 8;
+ sample += IMA4Codeword[nibble] * IMAStep_size[static_cast<uint>(index)] / 8;
sample = clampi(sample, -32768, 32767);
index += IMA4Index_adjust[nibble];
@@ -382,7 +382,7 @@ inline void LoadSamples<FmtMSADPCM>(float *RESTRICT dstSamples, const std::byte
int delta{int(input[2*srcChan + 0]) | (int(input[2*srcChan + 1]) << 8)};
input += srcStep*2;
- int sampleHistory[2]{};
+ std::array<int,2> sampleHistory{};
sampleHistory[0] = int(input[2*srcChan + 0]) | (int(input[2*srcChan + 1])<<8);
input += srcStep*2;
sampleHistory[1] = int(input[2*srcChan + 0]) | (int(input[2*srcChan + 1])<<8);
@@ -421,7 +421,7 @@ inline void LoadSamples<FmtMSADPCM>(float *RESTRICT dstSamples, const std::byte
sampleHistory[1] = sampleHistory[0];
sampleHistory[0] = pred;
- delta = (MSADPCMAdaption[nibble] * delta) / 256;
+ delta = (MSADPCMAdaption[static_cast<uint>(nibble)] * delta) / 256;
delta = maxi(16, delta);
return pred;
@@ -630,8 +630,8 @@ void DoHrtfMix(const float *samples, const uint DstBufferSize, DirectParams &par
parms.Hrtf.Target.Coeffs,
parms.Hrtf.Target.Delay,
0.0f, gain / static_cast<float>(fademix)};
- MixHrtfBlendSamples(HrtfSamples, AccumSamples+OutPos, IrSize, &parms.Hrtf.Old, &hrtfparams,
- fademix);
+ MixHrtfBlendSamples(HrtfSamples.data(), AccumSamples.data()+OutPos, IrSize,
+ &parms.Hrtf.Old, &hrtfparams, fademix);
/* Update the old parameters with the result. */
parms.Hrtf.Old = parms.Hrtf.Target;
@@ -658,7 +658,8 @@ void DoHrtfMix(const float *samples, const uint DstBufferSize, DirectParams &par
parms.Hrtf.Target.Delay,
parms.Hrtf.Old.Gain,
(gain - parms.Hrtf.Old.Gain) / static_cast<float>(todo)};
- MixHrtfSamples(HrtfSamples+fademix, AccumSamples+OutPos, IrSize, &hrtfparams, todo);
+ MixHrtfSamples(HrtfSamples.data()+fademix, AccumSamples.data()+OutPos, IrSize, &hrtfparams,
+ todo);
/* Store the now-current gain for next time. */
parms.Hrtf.Old.Gain = gain;
@@ -669,8 +670,8 @@ void DoNfcMix(const al::span<const float> samples, FloatBufferLine *OutBuffer, D
const float *TargetGains, const uint Counter, const uint OutPos, DeviceBase *Device)
{
using FilterProc = void (NfcFilter::*)(const al::span<const float>, float*);
- static constexpr FilterProc NfcProcess[MaxAmbiOrder+1]{
- nullptr, &NfcFilter::process1, &NfcFilter::process2, &NfcFilter::process3};
+ static constexpr std::array<FilterProc,MaxAmbiOrder+1> NfcProcess{{
+ nullptr, &NfcFilter::process1, &NfcFilter::process2, &NfcFilter::process3}};
float *CurrentGains{parms.Gains.Current.data()};
MixSamples(samples, {OutBuffer, 1u}, CurrentGains, TargetGains, Counter, OutPos);
@@ -678,7 +679,7 @@ void DoNfcMix(const al::span<const float> samples, FloatBufferLine *OutBuffer, D
++CurrentGains;
++TargetGains;
- const al::span<float> nfcsamples{Device->NfcSampleData, samples.size()};
+ const al::span<float> nfcsamples{Device->NfcSampleData.data(), samples.size()};
size_t order{1};
while(const size_t chancount{Device->NumChannelsPerOrder[order]})
{
@@ -697,7 +698,7 @@ void DoNfcMix(const al::span<const float> samples, FloatBufferLine *OutBuffer, D
void Voice::mix(const State vstate, ContextBase *Context, const nanoseconds deviceTime,
const uint SamplesToDo)
{
- static constexpr std::array<float,MAX_OUTPUT_CHANNELS> SilentTarget{};
+ static constexpr std::array<float,MaxOutputChannels> SilentTarget{};
ASSUME(SamplesToDo > 0);
@@ -903,8 +904,8 @@ void Voice::mix(const State vstate, ContextBase *Context, const nanoseconds devi
const size_t needBlocks{(needSamples + mSamplesPerBlock-1) / mSamplesPerBlock};
if(!mFlags.test(VoiceCallbackStopped) && needBlocks > mNumCallbackBlocks)
{
- const size_t byteOffset{mNumCallbackBlocks*mBytesPerBlock};
- const size_t needBytes{(needBlocks-mNumCallbackBlocks)*mBytesPerBlock};
+ const size_t byteOffset{mNumCallbackBlocks*size_t{mBytesPerBlock}};
+ const size_t needBytes{(needBlocks-mNumCallbackBlocks)*size_t{mBytesPerBlock}};
const int gotBytes{BufferListItem->mCallback(BufferListItem->mUserData,
&BufferListItem->mSamples[byteOffset], static_cast<int>(needBytes))};
@@ -918,7 +919,7 @@ void Voice::mix(const State vstate, ContextBase *Context, const nanoseconds devi
else
mNumCallbackBlocks = static_cast<uint>(needBlocks);
}
- const size_t numSamples{uint{mNumCallbackBlocks} * mSamplesPerBlock};
+ const size_t numSamples{size_t{mNumCallbackBlocks} * mSamplesPerBlock};
LoadBufferCallback(BufferListItem, bufferOffset, numSamples, mFmtType, chan,
mFrameStep, srcSampleDelay, srcBufferSize, al::to_address(resampleBuffer));
}
@@ -953,7 +954,7 @@ void Voice::mix(const State vstate, ContextBase *Context, const nanoseconds devi
fracPos += dstBufferSize*increment;
const uint srcOffset{fracPos >> MixerFracBits};
fracPos &= MixerFracMask;
- intPos += srcOffset;
+ intPos += static_cast<int>(srcOffset);
/* If more samples need to be loaded, copy the back of the
* resampleBuffer to the front to reuse it. prevSamples isn't
@@ -1017,7 +1018,7 @@ void Voice::mix(const State vstate, ContextBase *Context, const nanoseconds devi
if(mFlags.test(VoiceHasHrtf))
{
- const float TargetGain{parms.Hrtf.Target.Gain * (vstate == Playing)};
+ const float TargetGain{parms.Hrtf.Target.Gain * float(vstate == Playing)};
DoHrtfMix(samples, samplesToMix, parms, TargetGain, Counter, OutPos,
(vstate == Playing), Device);
}
@@ -1063,8 +1064,7 @@ void Voice::mix(const State vstate, ContextBase *Context, const nanoseconds devi
/* Update voice positions and buffers as needed. */
DataPosFrac += increment*samplesToMix;
- const uint SrcSamplesDone{DataPosFrac>>MixerFracBits};
- DataPosInt += SrcSamplesDone;
+ DataPosInt += static_cast<int>(DataPosFrac>>MixerFracBits);
DataPosFrac &= MixerFracMask;
uint buffers_done{0u};
@@ -1099,8 +1099,8 @@ void Voice::mix(const State vstate, ContextBase *Context, const nanoseconds devi
const uint blocksDone{currentBlock - mCallbackBlockBase};
if(blocksDone < mNumCallbackBlocks)
{
- const size_t byteOffset{blocksDone*mBytesPerBlock};
- const size_t byteEnd{mNumCallbackBlocks*mBytesPerBlock};
+ const size_t byteOffset{blocksDone*size_t{mBytesPerBlock}};
+ const size_t byteEnd{mNumCallbackBlocks*size_t{mBytesPerBlock}};
std::byte *data{BufferListItem->mSamples};
std::copy(data+byteOffset, data+byteEnd, data);
mNumCallbackBlocks -= blocksDone;
@@ -1120,7 +1120,7 @@ void Voice::mix(const State vstate, ContextBase *Context, const nanoseconds devi
if(BufferListItem->mSampleLen > static_cast<uint>(DataPosInt))
break;
- DataPosInt -= BufferListItem->mSampleLen;
+ DataPosInt -= static_cast<int>(BufferListItem->mSampleLen);
++buffers_done;
BufferListItem = BufferListItem->mNext.load(std::memory_order_relaxed);
diff --git a/core/voice.h b/core/voice.h
index a599eda8..f212ebe5 100644
--- a/core/voice.h
+++ b/core/voice.h
@@ -32,7 +32,7 @@ enum class DistanceModel : unsigned char;
using uint = unsigned int;
-#define MAX_SENDS 6
+inline constexpr size_t MaxSendCount{6};
enum class SpatializeMode : unsigned char {
@@ -48,7 +48,7 @@ enum class DirectMode : unsigned char {
};
-constexpr uint MaxPitch{10};
+inline constexpr uint MaxPitch{10};
enum {
@@ -66,14 +66,14 @@ struct DirectParams {
NfcFilter NFCtrlFilter;
struct {
- HrtfFilter Old;
- HrtfFilter Target;
- alignas(16) std::array<float,HrtfHistoryLength> History;
+ HrtfFilter Old{};
+ HrtfFilter Target{};
+ alignas(16) std::array<float,HrtfHistoryLength> History{};
} Hrtf;
struct {
- std::array<float,MAX_OUTPUT_CHANNELS> Current;
- std::array<float,MAX_OUTPUT_CHANNELS> Target;
+ std::array<float,MaxOutputChannels> Current{};
+ std::array<float,MaxOutputChannels> Target{};
} Gains;
};
@@ -82,8 +82,8 @@ struct SendParams {
BiquadFilter HighPass;
struct {
- std::array<float,MaxAmbiChannels> Current;
- std::array<float,MaxAmbiChannels> Target;
+ std::array<float,MaxAmbiChannels> Current{};
+ std::array<float,MaxAmbiChannels> Target{};
} Gains;
};
@@ -154,13 +154,12 @@ struct VoiceProps {
float HFReference;
float GainLF;
float LFReference;
- } Send[MAX_SENDS];
+ };
+ std::array<SendData,MaxSendCount> Send;
};
struct VoicePropsItem : public VoiceProps {
std::atomic<VoicePropsItem*> next{nullptr};
-
- DEF_NEWDEL(VoicePropsItem)
};
enum : uint {
@@ -185,7 +184,7 @@ struct Voice {
std::atomic<VoicePropsItem*> mUpdate{nullptr};
- VoiceProps mProps;
+ VoiceProps mProps{};
std::atomic<uint> mSourceID{0u};
std::atomic<State> mPlayState{Stopped};
@@ -195,30 +194,30 @@ struct Voice {
* Source offset in samples, relative to the currently playing buffer, NOT
* the whole queue.
*/
- std::atomic<int> mPosition;
+ std::atomic<int> mPosition{};
/** Fractional (fixed-point) offset to the next sample. */
- std::atomic<uint> mPositionFrac;
+ std::atomic<uint> mPositionFrac{};
/* Current buffer queue item being played. */
- std::atomic<VoiceBufferItem*> mCurrentBuffer;
+ std::atomic<VoiceBufferItem*> mCurrentBuffer{};
/* Buffer queue item to loop to at end of queue (will be NULL for non-
* looping voices).
*/
- std::atomic<VoiceBufferItem*> mLoopBuffer;
+ std::atomic<VoiceBufferItem*> mLoopBuffer{};
std::chrono::nanoseconds mStartTime{};
/* Properties for the attached buffer(s). */
- FmtChannels mFmtChannels;
- FmtType mFmtType;
- uint mFrequency;
- uint mFrameStep; /**< In steps of the sample type size. */
- uint mBytesPerBlock; /**< Or for PCM formats, BytesPerFrame. */
- uint mSamplesPerBlock; /**< Always 1 for PCM formats. */
- AmbiLayout mAmbiLayout;
- AmbiScaling mAmbiScaling;
- uint mAmbiOrder;
+ FmtChannels mFmtChannels{};
+ FmtType mFmtType{};
+ uint mFrequency{};
+ uint mFrameStep{}; /**< In steps of the sample type size. */
+ uint mBytesPerBlock{}; /**< Or for PCM formats, BytesPerFrame. */
+ uint mSamplesPerBlock{}; /**< Always 1 for PCM formats. */
+ AmbiLayout mAmbiLayout{};
+ AmbiScaling mAmbiScaling{};
+ uint mAmbiOrder{};
std::unique_ptr<DecoderBase> mDecoder;
uint mDecoderPadding{};
@@ -226,20 +225,20 @@ struct Voice {
/** Current target parameters used for mixing. */
uint mStep{0};
- ResamplerFunc mResampler;
+ ResamplerFunc mResampler{};
- InterpState mResampleState;
+ InterpState mResampleState{};
std::bitset<VoiceFlagCount> mFlags{};
uint mNumCallbackBlocks{0};
uint mCallbackBlockBase{0};
struct TargetData {
- int FilterType;
+ int FilterType{};
al::span<FloatBufferLine> Buffer;
};
TargetData mDirect;
- std::array<TargetData,MAX_SENDS> mSend;
+ std::array<TargetData,MaxSendCount> mSend;
/* The first MaxResamplerPadding/2 elements are the sample history from the
* previous mix, with an additional MaxResamplerPadding/2 elements that are
@@ -250,11 +249,11 @@ struct Voice {
al::vector<HistoryLine,16> mPrevSamples{2};
struct ChannelData {
- float mAmbiHFScale, mAmbiLFScale;
+ float mAmbiHFScale{}, mAmbiLFScale{};
BandSplitter mAmbiSplitter;
DirectParams mDryParams;
- std::array<SendParams,MAX_SENDS> mWetParams;
+ std::array<SendParams,MaxSendCount> mWetParams;
};
al::vector<ChannelData> mChans{2};
@@ -270,8 +269,6 @@ struct Voice {
void prepare(DeviceBase *device);
static void InitMixer(std::optional<std::string> resampler);
-
- DEF_NEWDEL(Voice)
};
extern Resampler ResamplerDefault;
diff --git a/core/voice_change.h b/core/voice_change.h
index ddc6186f..e97c48f3 100644
--- a/core/voice_change.h
+++ b/core/voice_change.h
@@ -3,8 +3,6 @@
#include <atomic>
-#include "almalloc.h"
-
struct Voice;
using uint = unsigned int;
@@ -24,8 +22,6 @@ struct VoiceChange {
VChangeState mState{};
std::atomic<VoiceChange*> mNext{nullptr};
-
- DEF_NEWDEL(VoiceChange)
};
#endif /* VOICE_CHANGE_H */
diff --git a/examples/alconvolve.c b/examples/alconvolve.c
index 8580d443..597d6ea2 100644
--- a/examples/alconvolve.c
+++ b/examples/alconvolve.c
@@ -38,6 +38,8 @@
#include "common/alhelpers.h"
+#include "win_main_utf8.h"
+
#ifndef AL_SOFT_convolution_effect
#define AL_SOFT_convolution_effect
@@ -88,11 +90,11 @@ static LPALGETAUXILIARYEFFECTSLOTFV alGetAuxiliaryEffectSlotfv;
/* This stuff defines a simple streaming player object, the same as alstream.c.
* Comments are removed for brevity, see alstream.c for more details.
*/
-#define NUM_BUFFERS 4
-#define BUFFER_SAMPLES 8192
+enum { NumBuffers = 4 };
+enum { BufferSamples = 8192 };
typedef struct StreamPlayer {
- ALuint buffers[NUM_BUFFERS];
+ ALuint buffers[NumBuffers];
ALuint source;
SNDFILE *sndfile;
@@ -109,7 +111,7 @@ static StreamPlayer *NewPlayer(void)
player = calloc(1, sizeof(*player));
assert(player != NULL);
- alGenBuffers(NUM_BUFFERS, player->buffers);
+ alGenBuffers(NumBuffers, player->buffers);
assert(alGetError() == AL_NO_ERROR && "Could not create buffers");
alGenSources(1, &player->source);
@@ -138,11 +140,11 @@ static void DeletePlayer(StreamPlayer *player)
ClosePlayerFile(player);
alDeleteSources(1, &player->source);
- alDeleteBuffers(NUM_BUFFERS, player->buffers);
+ alDeleteBuffers(NumBuffers, player->buffers);
if(alGetError() != AL_NO_ERROR)
fprintf(stderr, "Failed to delete object IDs\n");
- memset(player, 0, sizeof(*player));
+ memset(player, 0, sizeof(*player)); /* NOLINT(clang-analyzer-security.insecureAPI.*) */
free(player);
}
@@ -184,7 +186,7 @@ static int OpenPlayerFile(StreamPlayer *player, const char *filename)
return 0;
}
- frame_size = (size_t)(BUFFER_SAMPLES * player->sfinfo.channels) * sizeof(float);
+ frame_size = (size_t)(BufferSamples * player->sfinfo.channels) * sizeof(float);
player->membuf = malloc(frame_size);
return 1;
@@ -197,9 +199,9 @@ static int StartPlayer(StreamPlayer *player)
alSourceRewind(player->source);
alSourcei(player->source, AL_BUFFER, 0);
- for(i = 0;i < NUM_BUFFERS;i++)
+ for(i = 0;i < NumBuffers;i++)
{
- sf_count_t slen = sf_readf_float(player->sndfile, player->membuf, BUFFER_SAMPLES);
+ sf_count_t slen = sf_readf_float(player->sndfile, player->membuf, BufferSamples);
if(slen < 1) break;
slen *= player->sfinfo.channels * (sf_count_t)sizeof(float);
@@ -243,7 +245,7 @@ static int UpdatePlayer(StreamPlayer *player)
alSourceUnqueueBuffers(player->source, 1, &bufid);
processed--;
- slen = sf_readf_float(player->sndfile, player->membuf, BUFFER_SAMPLES);
+ slen = sf_readf_float(player->sndfile, player->membuf, BufferSamples);
if(slen > 0)
{
slen *= player->sfinfo.channels * (sf_count_t)sizeof(float);
@@ -359,10 +361,10 @@ static ALuint LoadSound(const char *filename)
}
namepart = strrchr(filename, '/');
- if(namepart || (namepart=strrchr(filename, '\\')))
- namepart++;
- else
- namepart = filename;
+ if(!namepart) namepart = strrchr(filename, '\\');
+ if(!namepart) namepart = filename;
+ else namepart++;
+
printf("Loading: %s (%s, %dhz, %" PRId64 " samples / %.2f seconds)\n", namepart,
FormatName(format), sfinfo.samplerate, sfinfo.frames,
(double)sfinfo.frames / sfinfo.samplerate);
@@ -555,10 +557,9 @@ int main(int argc, char **argv)
continue;
namepart = strrchr(argv[i], '/');
- if(namepart || (namepart=strrchr(argv[i], '\\')))
- namepart++;
- else
- namepart = argv[i];
+ if(!namepart) namepart = strrchr(argv[i], '\\');
+ if(!namepart) namepart = argv[i];
+ else namepart++;
printf("Playing: %s (%s, %dhz)\n", namepart, FormatName(player->format),
player->sfinfo.samplerate);
diff --git a/examples/alffplay.cpp b/examples/alffplay.cpp
index 1f02ef70..cfbe5564 100644
--- a/examples/alffplay.cpp
+++ b/examples/alffplay.cpp
@@ -285,7 +285,7 @@ struct AudioState {
AVStream *mStream{nullptr};
AVCodecCtxPtr mCodecCtx;
- DataQueue<2*1024*1024> mQueue;
+ DataQueue<size_t{2}*1024*1024> mQueue;
/* Used for clock difference average computation */
seconds_d64 mClockDiffAvg{0};
@@ -310,8 +310,9 @@ struct AudioState {
int mSamplesPos{0};
int mSamplesMax{0};
- std::unique_ptr<uint8_t[]> mBufferData;
- size_t mBufferDataSize{0};
+ std::vector<uint8_t> mBufferData_;
+ //std::unique_ptr<uint8_t[]> mBufferData;
+ //size_t mBufferDataSize{0};
std::atomic<size_t> mReadPos{0};
std::atomic<size_t> mWritePos{0};
@@ -321,7 +322,7 @@ struct AudioState {
std::mutex mSrcMutex;
std::condition_variable mSrcCond;
- std::atomic_flag mConnected;
+ std::atomic_flag mConnected{};
ALuint mSource{0};
std::array<ALuint,AudioBufferCount> mBuffers{};
ALuint mBufferIdx{0};
@@ -371,7 +372,7 @@ struct VideoState {
AVStream *mStream{nullptr};
AVCodecCtxPtr mCodecCtx;
- DataQueue<14*1024*1024> mQueue;
+ DataQueue<size_t{14}*1024*1024> mQueue;
/* The pts of the currently displayed frame, and the time (av_gettime) it
* was last updated - used to have running video pts
@@ -474,8 +475,8 @@ nanoseconds AudioState::getClockNoLock()
// Get the current device clock time and latency.
auto device = alcGetContextsDevice(alcGetCurrentContext());
- ALCint64SOFT devtimes[2]{0,0};
- alcGetInteger64vSOFT(device, ALC_DEVICE_CLOCK_LATENCY_SOFT, 2, devtimes);
+ std::array<ALCint64SOFT,2> devtimes{};
+ alcGetInteger64vSOFT(device, ALC_DEVICE_CLOCK_LATENCY_SOFT, 2, devtimes.data());
auto latency = nanoseconds{devtimes[1]};
auto device_time = nanoseconds{devtimes[0]};
@@ -485,7 +486,7 @@ nanoseconds AudioState::getClockNoLock()
return device_time - mDeviceStartTime - latency;
}
- if(mBufferDataSize > 0)
+ if(!mBufferData_.empty())
{
if(mDeviceStartTime == nanoseconds::min())
return nanoseconds::zero();
@@ -494,15 +495,14 @@ nanoseconds AudioState::getClockNoLock()
* actually the timestamp of the first sample frame played. The audio
* clock, then, is that plus the current source offset.
*/
- ALint64SOFT offset[2];
+ std::array<ALint64SOFT,2> offset{};
if(alGetSourcei64vSOFT)
- alGetSourcei64vSOFT(mSource, AL_SAMPLE_OFFSET_LATENCY_SOFT, offset);
+ alGetSourcei64vSOFT(mSource, AL_SAMPLE_OFFSET_LATENCY_SOFT, offset.data());
else
{
ALint ioffset;
alGetSourcei(mSource, AL_SAMPLE_OFFSET, &ioffset);
offset[0] = ALint64SOFT{ioffset} << 32;
- offset[1] = 0;
}
/* NOTE: The source state must be checked last, in case an underrun
* occurs and the source stops between getting the state and retrieving
@@ -523,7 +523,7 @@ nanoseconds AudioState::getClockNoLock()
*/
const size_t woffset{mWritePos.load(std::memory_order_acquire)};
const size_t roffset{mReadPos.load(std::memory_order_relaxed)};
- const size_t readable{((woffset >= roffset) ? woffset : (mBufferDataSize+woffset)) -
+ const size_t readable{((woffset>=roffset) ? woffset : (mBufferData_.size()+woffset)) -
roffset};
pts = mCurrentPts - nanoseconds{seconds{readable/mFrameSize}}/mCodecCtx->sample_rate;
@@ -550,15 +550,14 @@ nanoseconds AudioState::getClockNoLock()
nanoseconds pts{mCurrentPts};
if(mSource)
{
- ALint64SOFT offset[2];
+ std::array<ALint64SOFT,2> offset{};
if(alGetSourcei64vSOFT)
- alGetSourcei64vSOFT(mSource, AL_SAMPLE_OFFSET_LATENCY_SOFT, offset);
+ alGetSourcei64vSOFT(mSource, AL_SAMPLE_OFFSET_LATENCY_SOFT, offset.data());
else
{
ALint ioffset;
alGetSourcei(mSource, AL_SAMPLE_OFFSET, &ioffset);
offset[0] = ALint64SOFT{ioffset} << 32;
- offset[1] = 0;
}
ALint queued, status;
alGetSourcei(mSource, AL_BUFFERS_QUEUED, &queued);
@@ -586,10 +585,10 @@ bool AudioState::startPlayback()
{
const size_t woffset{mWritePos.load(std::memory_order_acquire)};
const size_t roffset{mReadPos.load(std::memory_order_relaxed)};
- const size_t readable{((woffset >= roffset) ? woffset : (mBufferDataSize+woffset)) -
+ const size_t readable{((woffset >= roffset) ? woffset : (mBufferData_.size()+woffset)) -
roffset};
- if(mBufferDataSize > 0)
+ if(!mBufferData_.empty())
{
if(readable == 0)
return false;
@@ -610,8 +609,8 @@ bool AudioState::startPlayback()
/* Subtract the total buffer queue time from the current pts to get the
* pts of the start of the queue.
*/
- int64_t srctimes[2]{0,0};
- alGetSourcei64vSOFT(mSource, AL_SAMPLE_OFFSET_CLOCK_SOFT, srctimes);
+ std::array<int64_t,2> srctimes{};
+ alGetSourcei64vSOFT(mSource, AL_SAMPLE_OFFSET_CLOCK_SOFT, srctimes.data());
auto device_time = nanoseconds{srctimes[1]};
auto src_offset = duration_cast<nanoseconds>(fixed32{srctimes[0]}) /
mCodecCtx->sample_rate;
@@ -622,7 +621,7 @@ bool AudioState::startPlayback()
* the device time the stream would have started at to reach where it
* is now.
*/
- if(mBufferDataSize > 0)
+ if(!mBufferData_.empty())
{
nanoseconds startpts{mCurrentPts -
nanoseconds{seconds{readable/mFrameSize}}/mCodecCtx->sample_rate};
@@ -739,8 +738,8 @@ bool AudioState::readAudio(uint8_t *samples, unsigned int length, int &sample_sk
{
const auto len = static_cast<unsigned int>(mSamplesLen - mSamplesPos);
if(rem > len) rem = len;
- std::copy_n(mSamples + static_cast<unsigned int>(mSamplesPos)*mFrameSize,
- rem*mFrameSize, samples);
+ std::copy_n(mSamples + static_cast<unsigned int>(mSamplesPos)*size_t{mFrameSize},
+ rem*size_t{mFrameSize}, samples);
}
else
{
@@ -750,9 +749,9 @@ bool AudioState::readAudio(uint8_t *samples, unsigned int length, int &sample_sk
sample_dup(samples, mSamples, rem, mFrameSize);
}
- mSamplesPos += rem;
+ mSamplesPos += static_cast<int>(rem);
mCurrentPts += nanoseconds{seconds{rem}} / mCodecCtx->sample_rate;
- samples += rem*mFrameSize;
+ samples += rem*size_t{mFrameSize};
audio_size += rem;
while(mSamplesPos >= mSamplesLen)
@@ -791,17 +790,17 @@ bool AudioState::readAudio(int sample_skip)
while(mSamplesLen > 0)
{
const size_t nsamples{((roffset > woffset) ? roffset-woffset-1
- : (roffset == 0) ? (mBufferDataSize-woffset-1)
- : (mBufferDataSize-woffset)) / mFrameSize};
+ : (roffset == 0) ? (mBufferData_.size()-woffset-1)
+ : (mBufferData_.size()-woffset)) / mFrameSize};
if(!nsamples) break;
if(mSamplesPos < 0)
{
const size_t rem{std::min<size_t>(nsamples, static_cast<ALuint>(-mSamplesPos))};
- sample_dup(&mBufferData[woffset], mSamples, rem, mFrameSize);
+ sample_dup(&mBufferData_[woffset], mSamples, rem, mFrameSize);
woffset += rem * mFrameSize;
- if(woffset == mBufferDataSize) woffset = 0;
+ if(woffset == mBufferData_.size()) woffset = 0;
mWritePos.store(woffset, std::memory_order_release);
mCurrentPts += nanoseconds{seconds{rem}} / mCodecCtx->sample_rate;
@@ -813,9 +812,9 @@ bool AudioState::readAudio(int sample_skip)
const size_t boffset{static_cast<ALuint>(mSamplesPos) * size_t{mFrameSize}};
const size_t nbytes{rem * mFrameSize};
- memcpy(&mBufferData[woffset], mSamples + boffset, nbytes);
+ memcpy(&mBufferData_[woffset], mSamples + boffset, nbytes);
woffset += nbytes;
- if(woffset == mBufferDataSize) woffset = 0;
+ if(woffset == mBufferData_.size()) woffset = 0;
mWritePos.store(woffset, std::memory_order_release);
mCurrentPts += nanoseconds{seconds{rem}} / mCodecCtx->sample_rate;
@@ -888,15 +887,15 @@ ALsizei AudioState::bufferCallback(void *data, ALsizei size) noexcept
const size_t woffset{mWritePos.load(std::memory_order_relaxed)};
if(woffset == roffset) break;
- size_t todo{((woffset < roffset) ? mBufferDataSize : woffset) - roffset};
+ size_t todo{((woffset < roffset) ? mBufferData_.size() : woffset) - roffset};
todo = std::min<size_t>(todo, static_cast<ALuint>(size-got));
- memcpy(data, &mBufferData[roffset], todo);
+ memcpy(data, &mBufferData_[roffset], todo);
data = static_cast<ALbyte*>(data) + todo;
got += static_cast<ALsizei>(todo);
roffset += todo;
- if(roffset == mBufferDataSize)
+ if(roffset == mBufferData_.size())
roffset = 0;
}
mReadPos.store(roffset, std::memory_order_release);
@@ -936,7 +935,7 @@ int AudioState::handler()
};
EventControlManager event_controller{sleep_time};
- std::unique_ptr<uint8_t[]> samples;
+ std::vector<uint8_t> samples;
ALsizei buffer_len{0};
/* Find a suitable format for OpenAL. */
@@ -1151,9 +1150,9 @@ int AudioState::handler()
mSwresCtx.reset(ps);
if(err != 0)
{
- char errstr[AV_ERROR_MAX_STRING_SIZE]{};
+ std::array<char,AV_ERROR_MAX_STRING_SIZE> errstr{};
std::cerr<< "Failed to allocate SwrContext: "
- <<av_make_error_string(errstr, AV_ERROR_MAX_STRING_SIZE, err) <<std::endl;
+ <<av_make_error_string(errstr.data(), AV_ERROR_MAX_STRING_SIZE, err) <<std::endl;
return 0;
}
@@ -1166,7 +1165,7 @@ int AudioState::handler()
* ordering and normalization, so a custom matrix is needed to
* scale and reorder the source from AmbiX.
*/
- std::vector<double> mtx(64*64, 0.0);
+ std::vector<double> mtx(size_t{64}*64, 0.0);
mtx[0 + 0*64] = std::sqrt(0.5);
mtx[3 + 1*64] = 1.0;
mtx[1 + 2*64] = 1.0;
@@ -1185,17 +1184,17 @@ int AudioState::handler()
mSwresCtx.reset(ps);
if(err != 0)
{
- char errstr[AV_ERROR_MAX_STRING_SIZE]{};
+ std::array<char,AV_ERROR_MAX_STRING_SIZE> errstr{};
std::cerr<< "Failed to allocate SwrContext: "
- <<av_make_error_string(errstr, AV_ERROR_MAX_STRING_SIZE, err) <<std::endl;
+ <<av_make_error_string(errstr.data(), AV_ERROR_MAX_STRING_SIZE, err) <<std::endl;
return 0;
}
}
if(int err{swr_init(mSwresCtx.get())})
{
- char errstr[AV_ERROR_MAX_STRING_SIZE]{};
+ std::array<char,AV_ERROR_MAX_STRING_SIZE> errstr{};
std::cerr<< "Failed to initialize audio converter: "
- <<av_make_error_string(errstr, AV_ERROR_MAX_STRING_SIZE, err) <<std::endl;
+ <<av_make_error_string(errstr.data(), AV_ERROR_MAX_STRING_SIZE, err) <<std::endl;
return 0;
}
@@ -1206,8 +1205,8 @@ int AudioState::handler()
alSourcei(mSource, AL_DIRECT_CHANNELS_SOFT, DirectOutMode);
if(EnableWideStereo)
{
- const float angles[2]{static_cast<float>(M_PI / 3.0), static_cast<float>(-M_PI / 3.0)};
- alSourcefv(mSource, AL_STEREO_ANGLES, angles);
+ const std::array angles{static_cast<float>(M_PI / 3.0), static_cast<float>(-M_PI / 3.0)};
+ alSourcefv(mSource, AL_STEREO_ANGLES, angles.data());
}
if(has_bfmt_ex)
{
@@ -1237,13 +1236,12 @@ int AudioState::handler()
}
else
{
- mBufferDataSize = static_cast<size_t>(duration_cast<seconds>(mCodecCtx->sample_rate *
- AudioBufferTotalTime).count()) * mFrameSize;
- mBufferData = std::make_unique<uint8_t[]>(mBufferDataSize);
- std::fill_n(mBufferData.get(), mBufferDataSize, uint8_t{});
+ mBufferData_.resize(static_cast<size_t>(duration_cast<seconds>(mCodecCtx->sample_rate *
+ AudioBufferTotalTime).count()) * mFrameSize);
+ std::fill(mBufferData_.begin(), mBufferData_.end(), uint8_t{});
mReadPos.store(0, std::memory_order_relaxed);
- mWritePos.store(mBufferDataSize/mFrameSize/2*mFrameSize, std::memory_order_relaxed);
+ mWritePos.store(mBufferData_.size()/mFrameSize/2*mFrameSize, std::memory_order_relaxed);
ALCint refresh{};
alcGetIntegerv(alcGetContextsDevice(alcGetCurrentContext()), ALC_REFRESH, 1, &refresh);
@@ -1255,12 +1253,12 @@ int AudioState::handler()
buffer_len = static_cast<int>(duration_cast<seconds>(mCodecCtx->sample_rate *
AudioBufferTime).count() * mFrameSize);
if(buffer_len > 0)
- samples = std::make_unique<uint8_t[]>(static_cast<ALuint>(buffer_len));
+ samples.resize(static_cast<ALuint>(buffer_len));
/* Prefill the codec buffer. */
auto packet_sender = [this]()
{
- while(1)
+ while(true)
{
const int ret{mQueue.sendPacket(mCodecCtx.get())};
if(ret == AVErrorEOF) break;
@@ -1287,7 +1285,7 @@ int AudioState::handler()
mCurrentPts += skip;
}
- while(1)
+ while(true)
{
if(mMovie.mQuit.load(std::memory_order_relaxed))
{
@@ -1299,11 +1297,11 @@ int AudioState::handler()
mSamplesLen = decodeFrame();
mSamplesPos = mSamplesLen;
} while(mSamplesLen > 0);
- goto finish;
+ break;
}
ALenum state;
- if(mBufferDataSize > 0)
+ if(!mBufferData_.empty())
{
alGetSourcei(mSource, AL_SOURCE_STATE, &state);
@@ -1333,13 +1331,13 @@ int AudioState::handler()
/* Read the next chunk of data, filling the buffer, and queue
* it on the source.
*/
- if(!readAudio(samples.get(), static_cast<ALuint>(buffer_len), sync_skip))
+ if(!readAudio(samples.data(), static_cast<ALuint>(buffer_len), sync_skip))
break;
const ALuint bufid{mBuffers[mBufferIdx]};
mBufferIdx = static_cast<ALuint>((mBufferIdx+1) % mBuffers.size());
- alBufferData(bufid, mFormat, samples.get(), buffer_len, mCodecCtx->sample_rate);
+ alBufferData(bufid, mFormat, samples.data(), buffer_len, mCodecCtx->sample_rate);
alSourceQueueBuffers(mSource, 1, &bufid);
++queued;
}
@@ -1380,7 +1378,6 @@ int AudioState::handler()
mSrcCond.wait_for(srclock, sleep_time);
}
-finish:
alSourceRewind(mSource);
alSourcei(mSource, AL_BUFFER, 0);
@@ -1451,7 +1448,7 @@ void VideoState::updateVideo(SDL_Window *screen, SDL_Renderer *renderer, bool re
auto clocktime = mMovie.getMasterClock();
bool updated{false};
- while(1)
+ while(true)
{
size_t next_idx{(read_idx+1)%mPictQ.size()};
if(next_idx == mPictQWrite.load(std::memory_order_acquire))
@@ -1511,9 +1508,9 @@ void VideoState::updateVideo(SDL_Window *screen, SDL_Renderer *renderer, bool re
{
double aspect_ratio = av_q2d(frame->sample_aspect_ratio);
if(aspect_ratio >= 1.0)
- frame_width = static_cast<int>(frame_width*aspect_ratio + 0.5);
+ frame_width = static_cast<int>(std::lround(frame_width * aspect_ratio));
else if(aspect_ratio > 0.0)
- frame_height = static_cast<int>(frame_height/aspect_ratio + 0.5);
+ frame_height = static_cast<int>(std::lround(frame_height / aspect_ratio));
}
SDL_SetWindowSize(screen, frame_width, frame_height);
}
@@ -1546,18 +1543,15 @@ void VideoState::updateVideo(SDL_Window *screen, SDL_Renderer *renderer, bool re
}
/* point pict at the queue */
- uint8_t *pict_data[3];
+ std::array<uint8_t*,3> pict_data;
pict_data[0] = static_cast<uint8_t*>(pixels);
- pict_data[1] = pict_data[0] + w*h;
- pict_data[2] = pict_data[1] + w*h/4;
+ pict_data[1] = pict_data[0] + ptrdiff_t{w}*h;
+ pict_data[2] = pict_data[1] + ptrdiff_t{w}*h/4;
- int pict_linesize[3];
- pict_linesize[0] = pitch;
- pict_linesize[1] = pitch / 2;
- pict_linesize[2] = pitch / 2;
+ std::array pict_linesize{pitch, pitch/2, pitch/2};
- sws_scale(mSwscaleCtx.get(), reinterpret_cast<uint8_t**>(frame->data), frame->linesize,
- 0, h, pict_data, pict_linesize);
+ sws_scale(mSwscaleCtx.get(), reinterpret_cast<uint8_t**>(frame->data),
+ frame->linesize, 0, h, pict_data.data(), pict_linesize.data());
SDL_UnlockTexture(mImage);
}
@@ -1599,7 +1593,7 @@ int VideoState::handler()
/* Prefill the codec buffer. */
auto packet_sender = [this]()
{
- while(1)
+ while(true)
{
const int ret{mQueue.sendPacket(mCodecCtx.get())};
if(ret == AVErrorEOF) break;
@@ -1613,7 +1607,7 @@ int VideoState::handler()
}
auto current_pts = nanoseconds::zero();
- while(1)
+ while(true)
{
size_t write_idx{mPictQWrite.load(std::memory_order_relaxed)};
Picture *vp{&mPictQ[write_idx]};
@@ -2062,7 +2056,7 @@ int main(int argc, char *argv[])
while(fileidx < argc && !movState)
{
- movState = std::unique_ptr<MovieState>{new MovieState{argv[fileidx++]}};
+ movState = std::make_unique<MovieState>(argv[fileidx++]);
if(!movState->prepare()) movState = nullptr;
}
if(!movState)
@@ -2077,7 +2071,7 @@ int main(int argc, char *argv[])
Next, Quit
} eom_action{EomAction::Next};
seconds last_time{seconds::min()};
- while(1)
+ while(true)
{
/* SDL_WaitEventTimeout is broken, just force a 10ms sleep. */
std::this_thread::sleep_for(milliseconds{10});
@@ -2145,7 +2139,7 @@ int main(int argc, char *argv[])
movState = nullptr;
while(fileidx < argc && !movState)
{
- movState = std::unique_ptr<MovieState>{new MovieState{argv[fileidx++]}};
+ movState = std::make_unique<MovieState>(argv[fileidx++]);
if(!movState->prepare()) movState = nullptr;
}
if(movState)
diff --git a/examples/alhrtf.c b/examples/alhrtf.c
index 7ea1b99e..a2f1824a 100644
--- a/examples/alhrtf.c
+++ b/examples/alhrtf.c
@@ -40,6 +40,8 @@
#include "common/alhelpers.h"
+#include "win_main_utf8.h"
+
#ifndef M_PI
#define M_PI (3.14159265358979323846)
diff --git a/examples/allatency.c b/examples/allatency.c
index 01f4eb69..9a535442 100644
--- a/examples/allatency.c
+++ b/examples/allatency.c
@@ -37,6 +37,8 @@
#include "common/alhelpers.h"
+#include "win_main_utf8.h"
+
static LPALSOURCEDSOFT alSourcedSOFT;
static LPALSOURCE3DSOFT alSource3dSOFT;
diff --git a/examples/almultireverb.c b/examples/almultireverb.c
index dcb76c87..f9a46c4f 100644
--- a/examples/almultireverb.c
+++ b/examples/almultireverb.c
@@ -47,6 +47,8 @@
#include "common/alhelpers.h"
+#include "win_main_utf8.h"
+
#ifndef M_PI
#define M_PI 3.14159265358979323846
@@ -106,7 +108,8 @@ static int LoadEffect(ALuint effect, const EFXEAXREVERBPROPERTIES *reverb)
* the needed panning vectors).
*/
alEffecti(effect, AL_EFFECT_TYPE, AL_EFFECT_EAXREVERB);
- if((err=alGetError()) != AL_NO_ERROR)
+ err = alGetError();
+ if(err != AL_NO_ERROR)
{
fprintf(stderr, "Failed to set EAX Reverb: %s (0x%04x)\n", alGetString(err), err);
return 0;
@@ -138,7 +141,8 @@ static int LoadEffect(ALuint effect, const EFXEAXREVERBPROPERTIES *reverb)
alEffecti(effect, AL_EAXREVERB_DECAY_HFLIMIT, reverb->iDecayHFLimit);
/* Check if an error occurred, and return failure if so. */
- if((err=alGetError()) != AL_NO_ERROR)
+ err = alGetError();
+ if(err != AL_NO_ERROR)
{
fprintf(stderr, "Error setting up reverb: %s\n", alGetString(err));
return 0;
diff --git a/examples/alplay.c b/examples/alplay.c
index 1eabcccd..9af7ca40 100644
--- a/examples/alplay.c
+++ b/examples/alplay.c
@@ -37,6 +37,8 @@
#include "common/alhelpers.h"
+#include "win_main_utf8.h"
+
enum FormatType {
Int16,
diff --git a/examples/alreverb.c b/examples/alreverb.c
index ff49db25..15b92235 100644
--- a/examples/alreverb.c
+++ b/examples/alreverb.c
@@ -40,6 +40,8 @@
#include "common/alhelpers.h"
+#include "win_main_utf8.h"
+
/* Effect object functions */
static LPALGENEFFECTS alGenEffects;
diff --git a/examples/alstream.c b/examples/alstream.c
index a61680d2..028290f5 100644
--- a/examples/alstream.c
+++ b/examples/alstream.c
@@ -37,13 +37,15 @@
#include "common/alhelpers.h"
+#include "win_main_utf8.h"
+
/* Define the number of buffers and buffer size (in milliseconds) to use. 4
* buffers at 200ms each gives a nice per-chunk size, and lets the queue last
* for almost one second.
*/
-#define NUM_BUFFERS 4
-#define BUFFER_MILLISEC 200
+enum { NumBuffers = 4 };
+enum { BufferMillisec = 200 };
typedef enum SampleType {
Int16, Float, IMA4, MSADPCM
@@ -51,7 +53,7 @@ typedef enum SampleType {
typedef struct StreamPlayer {
/* These are the buffers and source to play out through OpenAL with. */
- ALuint buffers[NUM_BUFFERS];
+ ALuint buffers[NumBuffers];
ALuint source;
/* Handle for the audio file */
@@ -88,7 +90,7 @@ static StreamPlayer *NewPlayer(void)
assert(player != NULL);
/* Generate the buffers and source */
- alGenBuffers(NUM_BUFFERS, player->buffers);
+ alGenBuffers(NumBuffers, player->buffers);
assert(alGetError() == AL_NO_ERROR && "Could not create buffers");
alGenSources(1, &player->source);
@@ -111,11 +113,11 @@ static void DeletePlayer(StreamPlayer *player)
ClosePlayerFile(player);
alDeleteSources(1, &player->source);
- alDeleteBuffers(NUM_BUFFERS, player->buffers);
+ alDeleteBuffers(NumBuffers, player->buffers);
if(alGetError() != AL_NO_ERROR)
fprintf(stderr, "Failed to delete object IDs\n");
- memset(player, 0, sizeof(*player));
+ memset(player, 0, sizeof(*player)); /* NOLINT(clang-analyzer-security.insecureAPI.*) */
free(player);
}
@@ -291,8 +293,8 @@ static int OpenPlayerFile(StreamPlayer *player, const char *filename)
}
player->block_count = player->sfinfo.samplerate / player->sampleblockalign;
- player->block_count = player->block_count * BUFFER_MILLISEC / 1000;
- player->membuf = malloc((size_t)(player->block_count * player->byteblockalign));
+ player->block_count = player->block_count * BufferMillisec / 1000;
+ player->membuf = malloc((size_t)player->block_count * (size_t)player->byteblockalign);
return 1;
}
@@ -310,7 +312,7 @@ static void ClosePlayerFile(StreamPlayer *player)
if(player->sampleblockalign > 1)
{
ALsizei i;
- for(i = 0;i < NUM_BUFFERS;i++)
+ for(i = 0;i < NumBuffers;i++)
alBufferi(player->buffers[i], AL_UNPACK_BLOCK_ALIGNMENT_SOFT, 0);
player->sampleblockalign = 0;
player->byteblockalign = 0;
@@ -328,7 +330,7 @@ static int StartPlayer(StreamPlayer *player)
alSourcei(player->source, AL_BUFFER, 0);
/* Fill the buffer queue */
- for(i = 0;i < NUM_BUFFERS;i++)
+ for(i = 0;i < NumBuffers;i++)
{
sf_count_t slen;
@@ -336,21 +338,21 @@ static int StartPlayer(StreamPlayer *player)
if(player->sample_type == Int16)
{
slen = sf_readf_short(player->sndfile, player->membuf,
- player->block_count * player->sampleblockalign);
+ (sf_count_t)player->block_count * player->sampleblockalign);
if(slen < 1) break;
slen *= player->byteblockalign;
}
else if(player->sample_type == Float)
{
slen = sf_readf_float(player->sndfile, player->membuf,
- player->block_count * player->sampleblockalign);
+ (sf_count_t)player->block_count * player->sampleblockalign);
if(slen < 1) break;
slen *= player->byteblockalign;
}
else
{
slen = sf_read_raw(player->sndfile, player->membuf,
- player->block_count * player->byteblockalign);
+ (sf_count_t)player->block_count * player->byteblockalign);
if(slen > 0) slen -= slen%player->byteblockalign;
if(slen < 1) break;
}
@@ -407,19 +409,19 @@ static int UpdatePlayer(StreamPlayer *player)
if(player->sample_type == Int16)
{
slen = sf_readf_short(player->sndfile, player->membuf,
- player->block_count * player->sampleblockalign);
+ (sf_count_t)player->block_count * player->sampleblockalign);
if(slen > 0) slen *= player->byteblockalign;
}
else if(player->sample_type == Float)
{
slen = sf_readf_float(player->sndfile, player->membuf,
- player->block_count * player->sampleblockalign);
+ (sf_count_t)player->block_count * player->sampleblockalign);
if(slen > 0) slen *= player->byteblockalign;
}
else
{
slen = sf_read_raw(player->sndfile, player->membuf,
- player->block_count * player->byteblockalign);
+ (sf_count_t)player->block_count * player->byteblockalign);
if(slen > 0) slen -= slen%player->byteblockalign;
}
@@ -486,10 +488,9 @@ int main(int argc, char **argv)
/* Get the name portion, without the path, for display. */
namepart = strrchr(argv[i], '/');
- if(namepart || (namepart=strrchr(argv[i], '\\')))
- namepart++;
- else
- namepart = argv[i];
+ if(!namepart) namepart = strrchr(argv[i], '\\');
+ if(!namepart) namepart = argv[i];
+ else namepart++;
printf("Playing: %s (%s, %dhz)\n", namepart, FormatName(player->format),
player->sfinfo.samplerate);
diff --git a/examples/alstreamcb.cpp b/examples/alstreamcb.cpp
index 6cc24034..ebf3d3b0 100644
--- a/examples/alstreamcb.cpp
+++ b/examples/alstreamcb.cpp
@@ -24,12 +24,12 @@
/* This file contains a streaming audio player using a callback buffer. */
-#include <string.h>
-#include <stdlib.h>
-#include <stdio.h>
#include <atomic>
#include <chrono>
+#include <cstring>
+#include <cstdlib>
+#include <cstdio>
#include <memory>
#include <stdexcept>
#include <string>
@@ -44,6 +44,8 @@
#include "common/alhelpers.h"
+#include "win_main_utf8.h"
+
namespace {
@@ -56,8 +58,7 @@ struct StreamPlayer {
/* A lockless ring-buffer (supports single-provider, single-consumer
* operation).
*/
- std::unique_ptr<ALbyte[]> mBufferData;
- size_t mBufferDataSize{0};
+ std::vector<ALbyte> mBufferData;
std::atomic<size_t> mReadPos{0};
std::atomic<size_t> mWritePos{0};
size_t mSamplesPerBlock{1};
@@ -78,7 +79,7 @@ struct StreamPlayer {
size_t mDecoderOffset{0};
/* The format of the callback samples. */
- ALenum mFormat;
+ ALenum mFormat{};
StreamPlayer()
{
@@ -166,8 +167,8 @@ struct StreamPlayer {
mSampleFormat = SampleType::Int16;
else
{
- auto fmtbuf = std::make_unique<ALubyte[]>(inf.datalen);
- inf.data = fmtbuf.get();
+ auto fmtbuf = std::vector<ALubyte>(inf.datalen);
+ inf.data = fmtbuf.data();
if(sf_get_chunk_data(iter, &inf) != SF_ERR_NO_ERROR)
mSampleFormat = SampleType::Int16;
else
@@ -194,12 +195,12 @@ struct StreamPlayer {
if(mSampleFormat == SampleType::Int16)
{
mSamplesPerBlock = 1;
- mBytesPerBlock = static_cast<size_t>(mSfInfo.channels * 2);
+ mBytesPerBlock = static_cast<size_t>(mSfInfo.channels) * 2;
}
else if(mSampleFormat == SampleType::Float)
{
mSamplesPerBlock = 1;
- mBytesPerBlock = static_cast<size_t>(mSfInfo.channels * 4);
+ mBytesPerBlock = static_cast<size_t>(mSfInfo.channels) * 4;
}
else
{
@@ -232,7 +233,7 @@ struct StreamPlayer {
}
else if(mSfInfo.channels == 3)
{
- if(sf_command(mSndfile, SFC_WAVEX_GET_AMBISONIC, NULL, 0) == SF_AMBISONIC_B_FORMAT)
+ if(sf_command(mSndfile, SFC_WAVEX_GET_AMBISONIC, nullptr, 0) == SF_AMBISONIC_B_FORMAT)
{
if(mSampleFormat == SampleType::Int16)
mFormat = AL_FORMAT_BFORMAT2D_16;
@@ -242,7 +243,7 @@ struct StreamPlayer {
}
else if(mSfInfo.channels == 4)
{
- if(sf_command(mSndfile, SFC_WAVEX_GET_AMBISONIC, NULL, 0) == SF_AMBISONIC_B_FORMAT)
+ if(sf_command(mSndfile, SFC_WAVEX_GET_AMBISONIC, nullptr, 0) == SF_AMBISONIC_B_FORMAT)
{
if(mSampleFormat == SampleType::Int16)
mFormat = AL_FORMAT_BFORMAT3D_16;
@@ -262,8 +263,7 @@ struct StreamPlayer {
/* Set a 1s ring buffer size. */
size_t numblocks{(static_cast<ALuint>(mSfInfo.samplerate) + mSamplesPerBlock-1)
/ mSamplesPerBlock};
- mBufferDataSize = static_cast<ALuint>(numblocks * mBytesPerBlock);
- mBufferData.reset(new ALbyte[mBufferDataSize]);
+ mBufferData.resize(static_cast<ALuint>(numblocks * mBytesPerBlock));
mReadPos.store(0, std::memory_order_relaxed);
mWritePos.store(0, std::memory_order_relaxed);
mDecoderOffset = 0;
@@ -303,7 +303,7 @@ struct StreamPlayer {
* that case, otherwise read up to the write offset. Also limit the
* amount to copy given how much is remaining to write.
*/
- size_t todo{((woffset < roffset) ? mBufferDataSize : woffset) - roffset};
+ size_t todo{((woffset < roffset) ? mBufferData.size() : woffset) - roffset};
todo = std::min<size_t>(todo, static_cast<ALuint>(size-got));
/* Copy from the ring buffer to the provided output buffer. Wrap
@@ -315,7 +315,7 @@ struct StreamPlayer {
got += static_cast<ALsizei>(todo);
roffset += todo;
- if(roffset == mBufferDataSize)
+ if(roffset == mBufferData.size())
roffset = 0;
}
/* Finally, store the updated read offset, and return how many bytes
@@ -351,7 +351,7 @@ struct StreamPlayer {
if(state != AL_INITIAL)
{
const size_t roffset{mReadPos.load(std::memory_order_relaxed)};
- const size_t readable{((woffset >= roffset) ? woffset : (mBufferDataSize+woffset)) -
+ const size_t readable{((woffset >= roffset) ? woffset : (mBufferData.size()+woffset)) -
roffset};
/* For a stopped (underrun) source, the current playback offset is
* the current decoder offset excluding the readable buffered data.
@@ -362,7 +362,7 @@ struct StreamPlayer {
? (mDecoderOffset-readable) / mBytesPerBlock * mSamplesPerBlock
: (static_cast<ALuint>(pos) + mStartOffset/mBytesPerBlock*mSamplesPerBlock))
/ static_cast<ALuint>(mSfInfo.samplerate)};
- printf("\r%3zus (%3zu%% full)", curtime, readable * 100 / mBufferDataSize);
+ printf("\r%3zus (%3zu%% full)", curtime, readable * 100 / mBufferData.size());
}
else
fputs("Starting...", stdout);
@@ -415,8 +415,8 @@ struct StreamPlayer {
* data can fit, and calculate how much can go in front before
* wrapping.
*/
- const size_t writable{(!roffset ? mBufferDataSize-woffset-1 :
- (mBufferDataSize-woffset)) / mBytesPerBlock};
+ const size_t writable{(!roffset ? mBufferData.size()-woffset-1 :
+ (mBufferData.size()-woffset)) / mBytesPerBlock};
if(!writable) break;
if(mSampleFormat == SampleType::Int16)
@@ -444,7 +444,7 @@ struct StreamPlayer {
}
woffset += read_bytes;
- if(woffset == mBufferDataSize)
+ if(woffset == mBufferData.size())
woffset = 0;
}
mWritePos.store(woffset, std::memory_order_release);
@@ -459,7 +459,7 @@ struct StreamPlayer {
* what's available.
*/
const size_t roffset{mReadPos.load(std::memory_order_relaxed)};
- const size_t readable{((woffset >= roffset) ? woffset : (mBufferDataSize+woffset)) -
+ const size_t readable{((woffset >= roffset) ? woffset : (mBufferData.size()+woffset)) -
roffset};
if(readable == 0)
return false;
@@ -522,7 +522,8 @@ int main(int argc, char **argv)
/* Get the name portion, without the path, for display. */
const char *namepart{strrchr(argv[i], '/')};
- if(namepart || (namepart=strrchr(argv[i], '\\')))
+ if(!namepart) namepart = strrchr(argv[i], '\\');
+ if(namepart)
++namepart;
else
namepart = argv[i];
diff --git a/examples/altonegen.c b/examples/altonegen.c
index ec7f77bb..2fab783d 100644
--- a/examples/altonegen.c
+++ b/examples/altonegen.c
@@ -321,7 +321,6 @@ int main(int argc, char *argv[])
if(pos > last_pos)
{
- last_pos = 0;
printf("%d...\n", seconds - pos);
fflush(stdout);
}
diff --git a/include/AL/al.h b/include/AL/al.h
index 87274184..e9f8f3b1 100644
--- a/include/AL/al.h
+++ b/include/AL/al.h
@@ -1,6 +1,7 @@
#ifndef AL_AL_H
#define AL_AL_H
+/* NOLINTBEGIN */
#ifdef __cplusplus
extern "C" {
@@ -689,5 +690,6 @@ typedef void (AL_APIENTRY *LPALDISTANCEMODEL)(ALenum distanceModel) AL_
#ifdef __cplusplus
} /* extern "C" */
#endif
+/* NOLINTEND */
#endif /* AL_AL_H */
diff --git a/include/AL/alc.h b/include/AL/alc.h
index 73dcf08f..3311b57f 100644
--- a/include/AL/alc.h
+++ b/include/AL/alc.h
@@ -1,6 +1,7 @@
#ifndef AL_ALC_H
#define AL_ALC_H
+/* NOLINTBEGIN */
#ifdef __cplusplus
extern "C" {
@@ -289,5 +290,6 @@ typedef void (ALC_APIENTRY *LPALCCAPTURESAMPLES)(ALCdevice *device, AL
#ifdef __cplusplus
} /* extern "C" */
#endif
+/* NOLINTEND */
#endif /* AL_ALC_H */
diff --git a/include/AL/alext.h b/include/AL/alext.h
index c75e0770..3f373704 100644
--- a/include/AL/alext.h
+++ b/include/AL/alext.h
@@ -1,6 +1,7 @@
#ifndef AL_ALEXT_H
#define AL_ALEXT_H
+/* NOLINTBEGIN */
#include <stddef.h>
/* Define int64 and uint64 types */
#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || \
@@ -737,5 +738,6 @@ void ALC_APIENTRY alcEventCallbackSOFT(ALCEVENTPROCTYPESOFT callback, void *user
#ifdef __cplusplus
}
#endif
+/* NOLINTEND */
#endif
diff --git a/include/AL/efx-presets.h b/include/AL/efx-presets.h
index 8539fd51..acd5bf39 100644
--- a/include/AL/efx-presets.h
+++ b/include/AL/efx-presets.h
@@ -2,6 +2,7 @@
#ifndef EFX_PRESETS_H
#define EFX_PRESETS_H
+/* NOLINTBEGIN */
#ifndef EFXEAXREVERBPROPERTIES_DEFINED
#define EFXEAXREVERBPROPERTIES_DEFINED
@@ -399,4 +400,5 @@ typedef struct {
#define EFX_REVERB_PRESET_SMALLWATERROOM \
{ 1.0000f, 0.7000f, 0.3162f, 0.4477f, 1.0000f, 1.5100f, 1.2500f, 1.1400f, 0.8913f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 1.4125f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.1790f, 0.1500f, 0.8950f, 0.1900f, 0.9920f, 5000.0000f, 250.0000f, 0.0000f, 0x0 }
+/* NOLINTEND */
#endif /* EFX_PRESETS_H */
diff --git a/include/AL/efx.h b/include/AL/efx.h
index f24222c3..1e93bf22 100644
--- a/include/AL/efx.h
+++ b/include/AL/efx.h
@@ -1,6 +1,7 @@
#ifndef AL_EFX_H
#define AL_EFX_H
+/* NOLINTBEGIN */
#include <float.h>
#include "alc.h"
@@ -758,5 +759,6 @@ AL_API void AL_APIENTRY alGetAuxiliaryEffectSlotfv(ALuint effectslot, ALenum par
#ifdef __cplusplus
} /* extern "C" */
#endif
+/* NOLINTEND */
#endif /* AL_EFX_H */
diff --git a/router/al.cpp b/router/al.cpp
index 6ed8a626..57c8d179 100644
--- a/router/al.cpp
+++ b/router/al.cpp
@@ -1,37 +1,42 @@
#include "config.h"
-#include <stddef.h>
+#include <cstddef>
#include "AL/al.h"
#include "router.h"
-#define DECL_THUNK1(R,n,T1) AL_API R AL_APIENTRY n(T1 a) noexcept \
+#define DECL_THUNK1(R,n,T1) \
+AL_API auto AL_APIENTRY n(T1 a) noexcept -> R \
{ \
DriverIface *iface = GetThreadDriver(); \
if(!iface) iface = CurrentCtxDriver.load(std::memory_order_acquire); \
return iface->n(a); \
}
-#define DECL_THUNK2(R,n,T1,T2) AL_API R AL_APIENTRY n(T1 a, T2 b) noexcept \
+#define DECL_THUNK2(R,n,T1,T2) \
+AL_API auto AL_APIENTRY n(T1 a, T2 b) noexcept -> R \
{ \
DriverIface *iface = GetThreadDriver(); \
if(!iface) iface = CurrentCtxDriver.load(std::memory_order_acquire); \
return iface->n(a, b); \
}
-#define DECL_THUNK3(R,n,T1,T2,T3) AL_API R AL_APIENTRY n(T1 a, T2 b, T3 c) noexcept \
+#define DECL_THUNK3(R,n,T1,T2,T3) \
+AL_API auto AL_APIENTRY n(T1 a, T2 b, T3 c) noexcept -> R \
{ \
DriverIface *iface = GetThreadDriver(); \
if(!iface) iface = CurrentCtxDriver.load(std::memory_order_acquire); \
return iface->n(a, b, c); \
}
-#define DECL_THUNK4(R,n,T1,T2,T3,T4) AL_API R AL_APIENTRY n(T1 a, T2 b, T3 c, T4 d) noexcept \
+#define DECL_THUNK4(R,n,T1,T2,T3,T4) \
+AL_API auto AL_APIENTRY n(T1 a, T2 b, T3 c, T4 d) noexcept -> R \
{ \
DriverIface *iface = GetThreadDriver(); \
if(!iface) iface = CurrentCtxDriver.load(std::memory_order_acquire); \
return iface->n(a, b, c, d); \
}
-#define DECL_THUNK5(R,n,T1,T2,T3,T4,T5) AL_API R AL_APIENTRY n(T1 a, T2 b, T3 c, T4 d, T5 e) noexcept \
+#define DECL_THUNK5(R,n,T1,T2,T3,T4,T5) \
+AL_API auto AL_APIENTRY n(T1 a, T2 b, T3 c, T4 d, T5 e) noexcept -> R \
{ \
DriverIface *iface = GetThreadDriver(); \
if(!iface) iface = CurrentCtxDriver.load(std::memory_order_acquire); \
@@ -42,7 +47,7 @@
/* Ugly hack for some apps calling alGetError without a current context, and
* expecting it to be AL_NO_ERROR.
*/
-AL_API ALenum AL_APIENTRY alGetError(void) noexcept
+AL_API auto AL_APIENTRY alGetError() noexcept -> ALenum
{
DriverIface *iface = GetThreadDriver();
if(!iface) iface = CurrentCtxDriver.load(std::memory_order_acquire);
diff --git a/router/alc.cpp b/router/alc.cpp
index fe9faa45..71deaf0b 100644
--- a/router/alc.cpp
+++ b/router/alc.cpp
@@ -6,9 +6,10 @@
#include <string.h>
#include <stdio.h>
-#include <mutex>
#include <algorithm>
#include <array>
+#include <mutex>
+#include <tuple>
#include "AL/alc.h"
#include "alstring.h"
@@ -413,12 +414,12 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *devicename) noexcep
{
std::lock_guard<std::recursive_mutex> _{EnumerationLock};
if(DevicesList.Names.empty())
- (void)alcGetString(nullptr, ALC_DEVICE_SPECIFIER);
+ std::ignore = alcGetString(nullptr, ALC_DEVICE_SPECIFIER);
idx = GetDriverIndexForName(&DevicesList, devicename);
if(idx < 0)
{
if(AllDevicesList.Names.empty())
- (void)alcGetString(nullptr, ALC_ALL_DEVICES_SPECIFIER);
+ std::ignore = alcGetString(nullptr, ALC_ALL_DEVICES_SPECIFIER);
idx = GetDriverIndexForName(&AllDevicesList, devicename);
}
}
@@ -578,7 +579,7 @@ ALC_API void ALC_APIENTRY alcDestroyContext(ALCcontext *context) noexcept
ContextIfaceMap.removeByKey(context);
}
-ALC_API ALCcontext* ALC_APIENTRY alcGetCurrentContext(void) noexcept
+ALC_API ALCcontext* ALC_APIENTRY alcGetCurrentContext() noexcept
{
DriverIface *iface = GetThreadDriver();
if(!iface) iface = CurrentCtxDriver.load();
@@ -884,7 +885,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *devicename,
{
std::lock_guard<std::recursive_mutex> _{EnumerationLock};
if(CaptureDevicesList.Names.empty())
- (void)alcGetString(nullptr, ALC_CAPTURE_DEVICE_SPECIFIER);
+ std::ignore = alcGetString(nullptr, ALC_CAPTURE_DEVICE_SPECIFIER);
idx = GetDriverIndexForName(&CaptureDevicesList, devicename);
}
@@ -1009,7 +1010,7 @@ ALC_API ALCboolean ALC_APIENTRY alcSetThreadContext(ALCcontext *context) noexcep
return ALC_FALSE;
}
-ALC_API ALCcontext* ALC_APIENTRY alcGetThreadContext(void) noexcept
+ALC_API ALCcontext* ALC_APIENTRY alcGetThreadContext() noexcept
{
DriverIface *iface = GetThreadDriver();
if(iface) return iface->alcGetThreadContext();
diff --git a/router/router.cpp b/router/router.cpp
index e2ba91d1..1fdf45ac 100644
--- a/router/router.cpp
+++ b/router/router.cpp
@@ -20,7 +20,7 @@
enum LogLevel LogLevel = LogLevel_Error;
FILE *LogFile;
-static void LoadDriverList(void);
+static void LoadDriverList();
BOOL APIENTRY DllMain(HINSTANCE, DWORD reason, void*)
@@ -313,7 +313,7 @@ static int GetLoadedModuleDirectory(const WCHAR *name, WCHAR *moddir, DWORD leng
return 1;
}
-void LoadDriverList(void)
+void LoadDriverList()
{
WCHAR dll_path[MAX_PATH+1] = L"";
WCHAR cwd_path[MAX_PATH+1] = L"";
@@ -361,7 +361,7 @@ void LoadDriverList(void)
PtrIntMap::~PtrIntMap()
{
std::lock_guard<std::mutex> maplock{mLock};
- al_free(mKeys);
+ free(mKeys);
mKeys = nullptr;
mValues = nullptr;
mSize = 0;
@@ -382,8 +382,7 @@ ALenum PtrIntMap::insert(void *key, int value)
ALsizei newcap{mCapacity ? (mCapacity<<1) : 4};
if(newcap > mCapacity)
newkeys = static_cast<void**>(
- al_calloc(16, (sizeof(mKeys[0])+sizeof(mValues[0]))*newcap)
- );
+ calloc(newcap, sizeof(mKeys[0])+sizeof(mValues[0])));
if(!newkeys)
return AL_OUT_OF_MEMORY;
auto newvalues = reinterpret_cast<int*>(&newkeys[newcap]);
@@ -393,7 +392,7 @@ ALenum PtrIntMap::insert(void *key, int value)
std::copy_n(mKeys, mSize, newkeys);
std::copy_n(mValues, mSize, newvalues);
}
- al_free(mKeys);
+ free(mKeys);
mKeys = newkeys;
mValues = newvalues;
mCapacity = newcap;
diff --git a/utils/alsoft-config/CMakeLists.txt b/utils/alsoft-config/CMakeLists.txt
index c6a46075..d9e6ca9a 100644
--- a/utils/alsoft-config/CMakeLists.txt
+++ b/utils/alsoft-config/CMakeLists.txt
@@ -12,7 +12,7 @@ if(Qt5Widgets_FOUND)
verstr.cpp
verstr.h
${UIS} ${RSCS} ${TRS} ${MOCS})
- target_link_libraries(alsoft-config Qt5::Widgets)
+ target_link_libraries(alsoft-config PUBLIC Qt5::Widgets PRIVATE alcommon)
target_include_directories(alsoft-config PRIVATE "${alsoft-config_BINARY_DIR}"
"${OpenAL_BINARY_DIR}")
set_target_properties(alsoft-config PROPERTIES ${DEFAULT_TARGET_PROPS}
diff --git a/utils/alsoft-config/mainwindow.cpp b/utils/alsoft-config/mainwindow.cpp
index bee7022f..9a65f79c 100644
--- a/utils/alsoft-config/mainwindow.cpp
+++ b/utils/alsoft-config/mainwindow.cpp
@@ -3,8 +3,9 @@
#include "mainwindow.h"
-#include <iostream>
+#include <array>
#include <cmath>
+#include <iostream>
#include <QFileDialog>
#include <QMessageBox>
@@ -19,137 +20,134 @@
#include <shlobj.h>
#endif
+#include "almalloc.h"
+#include "alspan.h"
+
namespace {
-const struct {
+struct BackendNamePair {
+ /* NOLINTBEGIN(*-avoid-c-arrays) */
char backend_name[16];
char full_string[32];
-} backendList[] = {
-#ifdef HAVE_JACK
- { "jack", "JACK" },
-#endif
+ /* NOLINTEND(*-avoid-c-arrays) */
+};
+constexpr std::array backendList{
#ifdef HAVE_PIPEWIRE
- { "pipewire", "PipeWire" },
+ BackendNamePair{ "pipewire", "PipeWire" },
#endif
#ifdef HAVE_PULSEAUDIO
- { "pulse", "PulseAudio" },
+ BackendNamePair{ "pulse", "PulseAudio" },
#endif
#ifdef HAVE_ALSA
- { "alsa", "ALSA" },
+ BackendNamePair{ "alsa", "ALSA" },
+#endif
+#ifdef HAVE_JACK
+ BackendNamePair{ "jack", "JACK" },
#endif
#ifdef HAVE_COREAUDIO
- { "core", "CoreAudio" },
+ BackendNamePair{ "core", "CoreAudio" },
#endif
#ifdef HAVE_OSS
- { "oss", "OSS" },
+ BackendNamePair{ "oss", "OSS" },
#endif
#ifdef HAVE_SOLARIS
- { "solaris", "Solaris" },
+ BackendNamePair{ "solaris", "Solaris" },
#endif
#ifdef HAVE_SNDIO
- { "sndio", "SoundIO" },
-#endif
-#ifdef HAVE_QSA
- { "qsa", "QSA" },
+ BackendNamePair{ "sndio", "SoundIO" },
#endif
#ifdef HAVE_WASAPI
- { "wasapi", "WASAPI" },
+ BackendNamePair{ "wasapi", "WASAPI" },
#endif
#ifdef HAVE_DSOUND
- { "dsound", "DirectSound" },
+ BackendNamePair{ "dsound", "DirectSound" },
#endif
#ifdef HAVE_WINMM
- { "winmm", "Windows Multimedia" },
+ BackendNamePair{ "winmm", "Windows Multimedia" },
#endif
#ifdef HAVE_PORTAUDIO
- { "port", "PortAudio" },
+ BackendNamePair{ "port", "PortAudio" },
#endif
#ifdef HAVE_OPENSL
- { "opensl", "OpenSL" },
+ BackendNamePair{ "opensl", "OpenSL" },
#endif
- { "null", "Null Output" },
+ BackendNamePair{ "null", "Null Output" },
#ifdef HAVE_WAVE
- { "wave", "Wave Writer" },
+ BackendNamePair{ "wave", "Wave Writer" },
#endif
- { "", "" }
};
-const struct NameValuePair {
+struct NameValuePair {
+ /* NOLINTBEGIN(*-avoid-c-arrays) */
const char name[64];
const char value[16];
-} speakerModeList[] = {
- { "Autodetect", "" },
- { "Mono", "mono" },
- { "Stereo", "stereo" },
- { "Quadraphonic", "quad" },
- { "5.1 Surround", "surround51" },
- { "6.1 Surround", "surround61" },
- { "7.1 Surround", "surround71" },
- { "3D7.1 Surround", "surround3d71" },
-
- { "Ambisonic, 1st Order", "ambi1" },
- { "Ambisonic, 2nd Order", "ambi2" },
- { "Ambisonic, 3rd Order", "ambi3" },
-
- { "", "" }
-}, sampleTypeList[] = {
- { "Autodetect", "" },
- { "8-bit int", "int8" },
- { "8-bit uint", "uint8" },
- { "16-bit int", "int16" },
- { "16-bit uint", "uint16" },
- { "32-bit int", "int32" },
- { "32-bit uint", "uint32" },
- { "32-bit float", "float32" },
-
- { "", "" }
-}, resamplerList[] = {
- { "Point", "point" },
- { "Linear", "linear" },
- { "Cubic Spline", "cubic" },
- { "Default (Cubic Spline)", "" },
- { "11th order Sinc (fast)", "fast_bsinc12" },
- { "11th order Sinc", "bsinc12" },
- { "23rd order Sinc (fast)", "fast_bsinc24" },
- { "23rd order Sinc", "bsinc24" },
-
- { "", "" }
-}, stereoModeList[] = {
- { "Autodetect", "" },
- { "Speakers", "speakers" },
- { "Headphones", "headphones" },
-
- { "", "" }
-}, stereoEncList[] = {
- { "Default", "" },
- { "Basic", "panpot" },
- { "UHJ", "uhj" },
- { "Binaural", "hrtf" },
-
- { "", "" }
-}, ambiFormatList[] = {
- { "Default", "" },
- { "AmbiX (ACN, SN3D)", "ambix" },
- { "Furse-Malham", "fuma" },
- { "ACN, N3D", "acn+n3d" },
- { "ACN, FuMa", "acn+fuma" },
-
- { "", "" }
-}, hrtfModeList[] = {
- { "1st Order Ambisonic", "ambi1" },
- { "2nd Order Ambisonic", "ambi2" },
- { "3rd Order Ambisonic", "ambi3" },
- { "Default (Full)", "" },
- { "Full", "full" },
-
- { "", "" }
+ /* NOLINTEND(*-avoid-c-arrays) */
+};
+constexpr std::array speakerModeList{
+ NameValuePair{ "Autodetect", "" },
+ NameValuePair{ "Mono", "mono" },
+ NameValuePair{ "Stereo", "stereo" },
+ NameValuePair{ "Quadraphonic", "quad" },
+ NameValuePair{ "5.1 Surround", "surround51" },
+ NameValuePair{ "6.1 Surround", "surround61" },
+ NameValuePair{ "7.1 Surround", "surround71" },
+ NameValuePair{ "3D7.1 Surround", "surround3d71" },
+
+ NameValuePair{ "Ambisonic, 1st Order", "ambi1" },
+ NameValuePair{ "Ambisonic, 2nd Order", "ambi2" },
+ NameValuePair{ "Ambisonic, 3rd Order", "ambi3" },
+};
+constexpr std::array sampleTypeList{
+ NameValuePair{ "Autodetect", "" },
+ NameValuePair{ "8-bit int", "int8" },
+ NameValuePair{ "8-bit uint", "uint8" },
+ NameValuePair{ "16-bit int", "int16" },
+ NameValuePair{ "16-bit uint", "uint16" },
+ NameValuePair{ "32-bit int", "int32" },
+ NameValuePair{ "32-bit uint", "uint32" },
+ NameValuePair{ "32-bit float", "float32" },
+};
+constexpr std::array resamplerList{
+ NameValuePair{ "Point", "point" },
+ NameValuePair{ "Linear", "linear" },
+ NameValuePair{ "Cubic Spline", "cubic" },
+ NameValuePair{ "Default (Cubic Spline)", "" },
+ NameValuePair{ "11th order Sinc (fast)", "fast_bsinc12" },
+ NameValuePair{ "11th order Sinc", "bsinc12" },
+ NameValuePair{ "23rd order Sinc (fast)", "fast_bsinc24" },
+ NameValuePair{ "23rd order Sinc", "bsinc24" },
+};
+constexpr std::array stereoModeList{
+ NameValuePair{ "Autodetect", "" },
+ NameValuePair{ "Speakers", "speakers" },
+ NameValuePair{ "Headphones", "headphones" },
+};
+constexpr std::array stereoEncList{
+ NameValuePair{ "Default", "" },
+ NameValuePair{ "Basic", "panpot" },
+ NameValuePair{ "UHJ", "uhj" },
+ NameValuePair{ "Binaural", "hrtf" },
+};
+constexpr std::array ambiFormatList{
+ NameValuePair{ "Default", "" },
+ NameValuePair{ "AmbiX (ACN, SN3D)", "ambix" },
+ NameValuePair{ "Furse-Malham", "fuma" },
+ NameValuePair{ "ACN, N3D", "acn+n3d" },
+ NameValuePair{ "ACN, FuMa", "acn+fuma" },
+};
+constexpr std::array hrtfModeList{
+ NameValuePair{ "1st Order Ambisonic", "ambi1" },
+ NameValuePair{ "2nd Order Ambisonic", "ambi2" },
+ NameValuePair{ "3rd Order Ambisonic", "ambi3" },
+ NameValuePair{ "Default (Full)", "" },
+ NameValuePair{ "Full", "full" },
};
QString getDefaultConfigName()
{
#ifdef Q_OS_WIN32
- static const char fname[] = "alsoft.ini";
+ static constexpr char fname[] = "alsoft.ini"; /* NOLINT(*-avoid-c-arrays) */
auto get_appdata_path = []() noexcept -> QString
{
WCHAR buffer[MAX_PATH];
@@ -159,7 +157,7 @@ QString getDefaultConfigName()
};
QString base = get_appdata_path();
#else
- static const char fname[] = "alsoft.conf";
+ static constexpr char fname[] = "alsoft.conf"; /* NOLINT(*-avoid-c-arrays) */
QByteArray base = qgetenv("XDG_CONFIG_HOME");
if(base.isEmpty())
{
@@ -226,10 +224,9 @@ QStringList getAllDataPaths(const QString &append)
return list;
}
-template<size_t N>
-QString getValueFromName(const NameValuePair (&list)[N], const QString &str)
+QString getValueFromName(const al::span<const NameValuePair> list, const QString &str)
{
- for(size_t i = 0;i < N-1;i++)
+ for(size_t i{0};i < list.size();++i)
{
if(str == list[i].name)
return list[i].value;
@@ -237,10 +234,9 @@ QString getValueFromName(const NameValuePair (&list)[N], const QString &str)
return QString{};
}
-template<size_t N>
-QString getNameFromValue(const NameValuePair (&list)[N], const QString &str)
+QString getNameFromValue(const al::span<const NameValuePair> list, const QString &str)
{
- for(size_t i = 0;i < N-1;i++)
+ for(size_t i{0};i < list.size();++i)
{
if(str == list[i].value)
return list[i].name;
@@ -270,44 +266,29 @@ QString getCheckValue(const QCheckBox *checkbox)
}
-MainWindow::MainWindow(QWidget *parent) :
- QMainWindow(parent),
- ui(new Ui::MainWindow),
- mPeriodSizeValidator(nullptr),
- mPeriodCountValidator(nullptr),
- mSourceCountValidator(nullptr),
- mEffectSlotValidator(nullptr),
- mSourceSendValidator(nullptr),
- mSampleRateValidator(nullptr),
- mJackBufferValidator(nullptr),
- mNeedsSave(false)
+MainWindow::MainWindow(QWidget *parent) : QMainWindow{parent}
+ , ui{std::make_unique<Ui::MainWindow>()}
{
ui->setupUi(this);
- for(int i = 0;speakerModeList[i].name[0];i++)
- ui->channelConfigCombo->addItem(speakerModeList[i].name);
+ for(auto &item : speakerModeList)
+ ui->channelConfigCombo->addItem(item.name);
ui->channelConfigCombo->adjustSize();
- for(int i = 0;sampleTypeList[i].name[0];i++)
- ui->sampleFormatCombo->addItem(sampleTypeList[i].name);
+ for(auto &item : sampleTypeList)
+ ui->sampleFormatCombo->addItem(item.name);
ui->sampleFormatCombo->adjustSize();
- for(int i = 0;stereoModeList[i].name[0];i++)
- ui->stereoModeCombo->addItem(stereoModeList[i].name);
+ for(auto &item : stereoModeList)
+ ui->stereoModeCombo->addItem(item.name);
ui->stereoModeCombo->adjustSize();
- for(int i = 0;stereoEncList[i].name[0];i++)
- ui->stereoEncodingComboBox->addItem(stereoEncList[i].name);
+ for(auto &item : stereoEncList)
+ ui->stereoEncodingComboBox->addItem(item.name);
ui->stereoEncodingComboBox->adjustSize();
- for(int i = 0;ambiFormatList[i].name[0];i++)
- ui->ambiFormatComboBox->addItem(ambiFormatList[i].name);
+ for(auto &item : ambiFormatList)
+ ui->ambiFormatComboBox->addItem(item.name);
ui->ambiFormatComboBox->adjustSize();
- int count;
- for(count = 0;resamplerList[count].name[0];count++) {
- }
- ui->resamplerSlider->setRange(0, count-1);
-
- for(count = 0;hrtfModeList[count].name[0];count++) {
- }
- ui->hrtfmodeSlider->setRange(0, count-1);
+ ui->resamplerSlider->setRange(0, resamplerList.size()-1);
+ ui->hrtfmodeSlider->setRange(0, hrtfModeList.size()-1);
#if !defined(HAVE_NEON) && !defined(HAVE_SSE)
ui->cpuExtDisabledLabel->move(ui->cpuExtDisabledLabel->x(), ui->cpuExtDisabledLabel->y() - 60);
@@ -355,22 +336,22 @@ MainWindow::MainWindow(QWidget *parent) :
ui->enableEaxCheck->setVisible(false);
#endif
- mPeriodSizeValidator = new QIntValidator{64, 8192, this};
- ui->periodSizeEdit->setValidator(mPeriodSizeValidator);
- mPeriodCountValidator = new QIntValidator{2, 16, this};
- ui->periodCountEdit->setValidator(mPeriodCountValidator);
+ mPeriodSizeValidator = std::make_unique<QIntValidator>(64, 8192, this);
+ ui->periodSizeEdit->setValidator(mPeriodSizeValidator.get());
+ mPeriodCountValidator = std::make_unique<QIntValidator>(2, 16, this);
+ ui->periodCountEdit->setValidator(mPeriodCountValidator.get());
- mSourceCountValidator = new QIntValidator{0, 4096, this};
- ui->srcCountLineEdit->setValidator(mSourceCountValidator);
- mEffectSlotValidator = new QIntValidator{0, 64, this};
- ui->effectSlotLineEdit->setValidator(mEffectSlotValidator);
- mSourceSendValidator = new QIntValidator{0, 16, this};
- ui->srcSendLineEdit->setValidator(mSourceSendValidator);
- mSampleRateValidator = new QIntValidator{8000, 192000, this};
- ui->sampleRateCombo->lineEdit()->setValidator(mSampleRateValidator);
+ mSourceCountValidator = std::make_unique<QIntValidator>(0, 4096, this);
+ ui->srcCountLineEdit->setValidator(mSourceCountValidator.get());
+ mEffectSlotValidator = std::make_unique<QIntValidator>(0, 64, this);
+ ui->effectSlotLineEdit->setValidator(mEffectSlotValidator.get());
+ mSourceSendValidator = std::make_unique<QIntValidator>(0, 16, this);
+ ui->srcSendLineEdit->setValidator(mSourceSendValidator.get());
+ mSampleRateValidator = std::make_unique<QIntValidator>(8000, 192000, this);
+ ui->sampleRateCombo->lineEdit()->setValidator(mSampleRateValidator.get());
- mJackBufferValidator = new QIntValidator{0, 8192, this};
- ui->jackBufferSizeLine->setValidator(mJackBufferValidator);
+ mJackBufferValidator = std::make_unique<QIntValidator>(0, 8192, this);
+ ui->jackBufferSizeLine->setValidator(mJackBufferValidator.get());
connect(ui->actionLoad, &QAction::triggered, this, &MainWindow::loadConfigFromFile);
connect(ui->actionSave_As, &QAction::triggered, this, &MainWindow::saveConfigAsFile);
@@ -495,7 +476,7 @@ MainWindow::MainWindow(QWidget *parent) :
for(int i = 1;i < ui->backendListWidget->count();i++)
ui->backendListWidget->setRowHidden(i, true);
- for(int i = 0;backendList[i].backend_name[0];i++)
+ for(size_t i{0};i < backendList.size();++i)
{
QList<QListWidgetItem*> items = ui->backendListWidget->findItems(
backendList[i].full_string, Qt::MatchFixedString);
@@ -506,17 +487,7 @@ MainWindow::MainWindow(QWidget *parent) :
loadConfig(getDefaultConfigName());
}
-MainWindow::~MainWindow()
-{
- delete ui;
- delete mPeriodSizeValidator;
- delete mPeriodCountValidator;
- delete mSourceCountValidator;
- delete mEffectSlotValidator;
- delete mSourceSendValidator;
- delete mSampleRateValidator;
- delete mJackBufferValidator;
-}
+MainWindow::~MainWindow() = default;
void MainWindow::closeEvent(QCloseEvent *event)
{
@@ -583,7 +554,7 @@ QStringList MainWindow::collectHrtfs()
break;
}
++i;
- } while(1);
+ } while(true);
}
}
}
@@ -618,7 +589,7 @@ QStringList MainWindow::collectHrtfs()
break;
}
++i;
- } while(1);
+ } while(true);
}
}
}
@@ -789,11 +760,11 @@ void MainWindow::loadConfig(const QString &fname)
/* The "basic" mode name is no longer supported. Use "ambi2" instead. */
if(hrtfmode == "basic")
hrtfmode = "ambi2";
- for(int i = 0;hrtfModeList[i].name[0];i++)
+ for(size_t i{0};i < hrtfModeList.size();++i)
{
if(hrtfmode == hrtfModeList[i].value)
{
- ui->hrtfmodeSlider->setValue(i);
+ ui->hrtfmodeSlider->setValue(static_cast<int>(i));
ui->hrtfmodeLabel->setText(hrtfModeList[i].name);
break;
}
@@ -869,7 +840,8 @@ void MainWindow::loadConfig(const QString &fname)
if(lastWasEmpty) continue;
if(!backend.startsWith(QChar('-')))
- for(int j = 0;backendList[j].backend_name[0];j++)
+ {
+ for(size_t j{0};j < backendList.size();++j)
{
if(backend == backendList[j].backend_name)
{
@@ -877,10 +849,11 @@ void MainWindow::loadConfig(const QString &fname)
break;
}
}
+ }
else if(backend.size() > 1)
{
QStringRef backendref{backend.rightRef(backend.size()-1)};
- for(int j = 0;backendList[j].backend_name[0];j++)
+ for(size_t j{0};j < backendList.size();++j)
{
if(backendref == backendList[j].backend_name)
{
@@ -1070,7 +1043,7 @@ void MainWindow::saveConfig(const QString &fname) const
for(int i = 0;i < ui->enabledBackendList->count();i++)
{
QString label{ui->enabledBackendList->item(i)->text()};
- for(int j = 0;backendList[j].backend_name[0];j++)
+ for(size_t j{0};j < backendList.size();++j)
{
if(label == backendList[j].full_string)
{
@@ -1082,7 +1055,7 @@ void MainWindow::saveConfig(const QString &fname) const
for(int i = 0;i < ui->disabledBackendList->count();i++)
{
QString label{ui->disabledBackendList->item(i)->text()};
- for(int j = 0;backendList[j].backend_name[0];j++)
+ for(size_t j{0};j < backendList.size();++j)
{
if(label == backendList[j].full_string)
{
@@ -1294,7 +1267,7 @@ void MainWindow::updateJackBufferSizeSlider()
void MainWindow::updateHrtfModeLabel(int num)
{
- ui->hrtfmodeLabel->setText(hrtfModeList[num].name);
+ ui->hrtfmodeLabel->setText(hrtfModeList[static_cast<uint>(num)].name);
enableApplyButton();
}
@@ -1311,11 +1284,10 @@ void MainWindow::addHrtfFile()
void MainWindow::removeHrtfFile()
{
- QList<QListWidgetItem*> selected{ui->hrtfFileList->selectedItems()};
+ QList<gsl::owner<QListWidgetItem*>> selected{ui->hrtfFileList->selectedItems()};
if(!selected.isEmpty())
{
- foreach(QListWidgetItem *item, selected)
- delete item;
+ std::for_each(selected.begin(), selected.end(), std::default_delete<QListWidgetItem>{});
enableApplyButton();
}
}
@@ -1336,7 +1308,7 @@ void MainWindow::showEnabledBackendMenu(QPoint pt)
if(ui->enabledBackendList->selectedItems().empty())
removeAction->setEnabled(false);
ctxmenu.addSeparator();
- for(size_t i = 0;backendList[i].backend_name[0];i++)
+ for(size_t i{0};i < backendList.size();++i)
{
QString backend{backendList[i].full_string};
QAction *action{ctxmenu.addAction(QString("Add ")+backend)};
@@ -1349,9 +1321,8 @@ void MainWindow::showEnabledBackendMenu(QPoint pt)
QAction *gotAction{ctxmenu.exec(pt)};
if(gotAction == removeAction)
{
- QList<QListWidgetItem*> selected{ui->enabledBackendList->selectedItems()};
- foreach(QListWidgetItem *item, selected)
- delete item;
+ QList<gsl::owner<QListWidgetItem*>> selected{ui->enabledBackendList->selectedItems()};
+ std::for_each(selected.begin(), selected.end(), std::default_delete<QListWidgetItem>{});
enableApplyButton();
}
else if(gotAction != nullptr)
@@ -1374,7 +1345,7 @@ void MainWindow::showDisabledBackendMenu(QPoint pt)
if(ui->disabledBackendList->selectedItems().empty())
removeAction->setEnabled(false);
ctxmenu.addSeparator();
- for(size_t i = 0;backendList[i].backend_name[0];i++)
+ for(size_t i{0};i < backendList.size();++i)
{
QString backend{backendList[i].full_string};
QAction *action{ctxmenu.addAction(QString("Add ")+backend)};
@@ -1387,9 +1358,8 @@ void MainWindow::showDisabledBackendMenu(QPoint pt)
QAction *gotAction{ctxmenu.exec(pt)};
if(gotAction == removeAction)
{
- QList<QListWidgetItem*> selected{ui->disabledBackendList->selectedItems()};
- foreach(QListWidgetItem *item, selected)
- delete item;
+ QList<gsl::owner<QListWidgetItem*>> selected{ui->disabledBackendList->selectedItems()};
+ std::for_each(selected.begin(), selected.end(), std::default_delete<QListWidgetItem>{});
enableApplyButton();
}
else if(gotAction != nullptr)
diff --git a/utils/alsoft-config/mainwindow.h b/utils/alsoft-config/mainwindow.h
index f7af8eac..96151ca2 100644
--- a/utils/alsoft-config/mainwindow.h
+++ b/utils/alsoft-config/mainwindow.h
@@ -1,6 +1,8 @@
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
+#include <memory>
+
#include <QMainWindow>
#include <QListWidget>
@@ -8,13 +10,12 @@ namespace Ui {
class MainWindow;
}
-class MainWindow : public QMainWindow
-{
+class MainWindow : public QMainWindow {
Q_OBJECT
public:
- explicit MainWindow(QWidget *parent = 0);
- ~MainWindow();
+ explicit MainWindow(QWidget *parent=nullptr);
+ ~MainWindow() override;
private slots:
void cancelCloseAction();
@@ -61,19 +62,19 @@ private slots:
void selectWaveOutput();
private:
- Ui::MainWindow *ui;
+ std::unique_ptr<QValidator> mPeriodSizeValidator;
+ std::unique_ptr<QValidator> mPeriodCountValidator;
+ std::unique_ptr<QValidator> mSourceCountValidator;
+ std::unique_ptr<QValidator> mEffectSlotValidator;
+ std::unique_ptr<QValidator> mSourceSendValidator;
+ std::unique_ptr<QValidator> mSampleRateValidator;
+ std::unique_ptr<QValidator> mJackBufferValidator;
- QValidator *mPeriodSizeValidator;
- QValidator *mPeriodCountValidator;
- QValidator *mSourceCountValidator;
- QValidator *mEffectSlotValidator;
- QValidator *mSourceSendValidator;
- QValidator *mSampleRateValidator;
- QValidator *mJackBufferValidator;
+ std::unique_ptr<Ui::MainWindow> ui;
- bool mNeedsSave;
+ bool mNeedsSave{};
- void closeEvent(QCloseEvent *event);
+ void closeEvent(QCloseEvent *event) override;
void selectDecoderFile(QLineEdit *line, const char *name);
diff --git a/utils/makemhr/loaddef.cpp b/utils/makemhr/loaddef.cpp
index c8a98511..f01e93fc 100644
--- a/utils/makemhr/loaddef.cpp
+++ b/utils/makemhr/loaddef.cpp
@@ -34,9 +34,13 @@
#include <limits>
#include <memory>
#include <optional>
+#include <string>
+#include <string_view>
#include <vector>
+#include "albit.h"
#include "alfstream.h"
+#include "alnumeric.h"
#include "alspan.h"
#include "alstring.h"
#include "makemhr.h"
@@ -45,12 +49,12 @@
#include "mysofa.h"
// Constants for accessing the token reader's ring buffer.
-#define TR_RING_BITS (16)
-#define TR_RING_SIZE (1 << TR_RING_BITS)
-#define TR_RING_MASK (TR_RING_SIZE - 1)
+constexpr uint TRRingBits{16};
+constexpr uint TRRingSize{1 << TRRingBits};
+constexpr uint TRRingMask{TRRingSize - 1};
// The token reader's load interval in bytes.
-#define TR_LOAD_SIZE (TR_RING_SIZE >> 2)
+constexpr uint TRLoadSize{TRRingSize >> 2};
// Token reader state for parsing the data set definition.
struct TokenReaderT {
@@ -58,7 +62,7 @@ struct TokenReaderT {
const char *mName{};
uint mLine{};
uint mColumn{};
- char mRing[TR_RING_SIZE]{};
+ std::array<char,TRRingSize> mRing{};
std::streamsize mIn{};
std::streamsize mOut{};
@@ -69,44 +73,48 @@ struct TokenReaderT {
// The maximum identifier length used when processing the data set
// definition.
-#define MAX_IDENT_LEN (16)
+constexpr uint MaxIdentLen{16};
// The limits for the listener's head 'radius' in the data set definition.
-#define MIN_RADIUS (0.05)
-#define MAX_RADIUS (0.15)
+constexpr double MinRadius{0.05};
+constexpr double MaxRadius{0.15};
// The maximum number of channels that can be addressed for a WAVE file
// source listed in the data set definition.
-#define MAX_WAVE_CHANNELS (65535)
+constexpr uint MaxWaveChannels{65535};
// The limits to the byte size for a binary source listed in the definition
// file.
-#define MIN_BIN_SIZE (2)
-#define MAX_BIN_SIZE (4)
-
-// The minimum number of significant bits for binary sources listed in the
-// data set definition. The maximum is calculated from the byte size.
-#define MIN_BIN_BITS (16)
+enum : uint {
+ MinBinSize = 2,
+ MaxBinSize = 4
+};
// The limits to the number of significant bits for an ASCII source listed in
// the data set definition.
-#define MIN_ASCII_BITS (16)
-#define MAX_ASCII_BITS (32)
+enum : uint {
+ MinASCIIBits = 16,
+ MaxASCIIBits = 32
+};
// The four-character-codes for RIFF/RIFX WAVE file chunks.
-#define FOURCC_RIFF (0x46464952) // 'RIFF'
-#define FOURCC_RIFX (0x58464952) // 'RIFX'
-#define FOURCC_WAVE (0x45564157) // 'WAVE'
-#define FOURCC_FMT (0x20746D66) // 'fmt '
-#define FOURCC_DATA (0x61746164) // 'data'
-#define FOURCC_LIST (0x5453494C) // 'LIST'
-#define FOURCC_WAVL (0x6C766177) // 'wavl'
-#define FOURCC_SLNT (0x746E6C73) // 'slnt'
+enum : uint {
+ FOURCC_RIFF = 0x46464952, // 'RIFF'
+ FOURCC_RIFX = 0x58464952, // 'RIFX'
+ FOURCC_WAVE = 0x45564157, // 'WAVE'
+ FOURCC_FMT = 0x20746D66, // 'fmt '
+ FOURCC_DATA = 0x61746164, // 'data'
+ FOURCC_LIST = 0x5453494C, // 'LIST'
+ FOURCC_WAVL = 0x6C766177, // 'wavl'
+ FOURCC_SLNT = 0x746E6C73, // 'slnt'
+};
// The supported wave formats.
-#define WAVE_FORMAT_PCM (0x0001)
-#define WAVE_FORMAT_IEEE_FLOAT (0x0003)
-#define WAVE_FORMAT_EXTENSIBLE (0xFFFE)
+enum : uint {
+ WAVE_FORMAT_PCM = 0x0001,
+ WAVE_FORMAT_IEEE_FLOAT = 0x0003,
+ WAVE_FORMAT_EXTENSIBLE = 0xFFFE,
+};
enum ByteOrderT {
@@ -144,7 +152,7 @@ struct SourceRefT {
double mRadius;
uint mSkip;
uint mOffset;
- char mPath[MAX_PATH_LEN+1];
+ std::array<char,MAX_PATH_LEN+1> mPath;
};
@@ -196,13 +204,14 @@ static int TrLoad(TokenReaderT *tr)
{
std::istream &istream = tr->mIStream;
- std::streamsize toLoad{TR_RING_SIZE - static_cast<std::streamsize>(tr->mIn - tr->mOut)};
- if(toLoad >= TR_LOAD_SIZE && istream.good())
+ std::streamsize toLoad{TRRingSize - static_cast<std::streamsize>(tr->mIn - tr->mOut)};
+ if(toLoad >= TRLoadSize && istream.good())
{
- // Load TR_LOAD_SIZE (or less if at the end of the file) per read.
- toLoad = TR_LOAD_SIZE;
- std::streamsize in{tr->mIn&TR_RING_MASK};
- std::streamsize count{TR_RING_SIZE - in};
+ // Load TRLoadSize (or less if at the end of the file) per read.
+ toLoad = TRLoadSize;
+
+ const auto in = static_cast<uint>(tr->mIn&TRRingMask);
+ std::streamsize count{TRRingSize - in};
if(count < toLoad)
{
istream.read(&tr->mRing[in], count);
@@ -216,10 +225,10 @@ static int TrLoad(TokenReaderT *tr)
tr->mIn += istream.gcount();
}
- if(tr->mOut >= TR_RING_SIZE)
+ if(tr->mOut >= TRRingSize)
{
- tr->mOut -= TR_RING_SIZE;
- tr->mIn -= TR_RING_SIZE;
+ tr->mOut -= TRRingSize;
+ tr->mIn -= TRRingSize;
}
}
if(tr->mIn > tr->mOut)
@@ -263,7 +272,7 @@ static void TrSkipLine(TokenReaderT *tr)
while(TrLoad(tr))
{
- ch = tr->mRing[tr->mOut&TR_RING_MASK];
+ ch = tr->mRing[tr->mOut&TRRingMask];
tr->mOut++;
if(ch == '\n')
{
@@ -280,7 +289,7 @@ static int TrSkipWhitespace(TokenReaderT *tr)
{
while(TrLoad(tr))
{
- char ch{tr->mRing[tr->mOut&TR_RING_MASK]};
+ char ch{tr->mRing[tr->mOut&TRRingMask]};
if(isspace(ch))
{
tr->mOut++;
@@ -314,7 +323,7 @@ static int TrIsIdent(TokenReaderT *tr)
{
if(!TrSkipWhitespace(tr))
return 0;
- char ch{tr->mRing[tr->mOut&TR_RING_MASK]};
+ char ch{tr->mRing[tr->mOut&TRRingMask]};
return ch == '_' || isalpha(ch);
}
@@ -333,7 +342,7 @@ static int TrIsOperator(TokenReaderT *tr, const char *op)
len = 0;
while(op[len] != '\0' && out < tr->mIn)
{
- ch = tr->mRing[out&TR_RING_MASK];
+ ch = tr->mRing[out&TRRingMask];
if(ch != op[len]) break;
len++;
out++;
@@ -358,7 +367,7 @@ static int TrReadIdent(TokenReaderT *tr, const uint maxLen, char *ident)
if(TrSkipWhitespace(tr))
{
col = tr->mColumn;
- ch = tr->mRing[tr->mOut&TR_RING_MASK];
+ ch = tr->mRing[tr->mOut&TRRingMask];
if(ch == '_' || isalpha(ch))
{
len = 0;
@@ -369,7 +378,7 @@ static int TrReadIdent(TokenReaderT *tr, const uint maxLen, char *ident)
tr->mOut++;
if(!TrLoad(tr))
break;
- ch = tr->mRing[tr->mOut&TR_RING_MASK];
+ ch = tr->mRing[tr->mOut&TRRingMask];
} while(ch == '_' || isdigit(ch) || isalpha(ch));
tr->mColumn += len;
@@ -389,25 +398,23 @@ static int TrReadIdent(TokenReaderT *tr, const uint maxLen, char *ident)
// Reads and validates (including bounds) an integer token.
static int TrReadInt(TokenReaderT *tr, const int loBound, const int hiBound, int *value)
{
- uint col, digis, len;
- char ch, temp[64+1];
-
- col = tr->mColumn;
+ uint col{tr->mColumn};
if(TrSkipWhitespace(tr))
{
col = tr->mColumn;
- len = 0;
- ch = tr->mRing[tr->mOut&TR_RING_MASK];
+ uint len{0};
+ std::array<char,64+1> temp{};
+ char ch{tr->mRing[tr->mOut&TRRingMask]};
if(ch == '+' || ch == '-')
{
temp[len] = ch;
len++;
tr->mOut++;
}
- digis = 0;
+ uint digis{0};
while(TrLoad(tr))
{
- ch = tr->mRing[tr->mOut&TR_RING_MASK];
+ ch = tr->mRing[tr->mOut&TRRingMask];
if(!isdigit(ch)) break;
if(len < 64)
temp[len] = ch;
@@ -424,7 +431,7 @@ static int TrReadInt(TokenReaderT *tr, const int loBound, const int hiBound, int
return 0;
}
temp[len] = '\0';
- *value = static_cast<int>(strtol(temp, nullptr, 10));
+ *value = static_cast<int>(strtol(temp.data(), nullptr, 10));
if(*value < loBound || *value > hiBound)
{
TrErrorAt(tr, tr->mLine, col, "Expected a value from %d to %d.\n", loBound, hiBound);
@@ -440,15 +447,13 @@ static int TrReadInt(TokenReaderT *tr, const int loBound, const int hiBound, int
// Reads and validates (including bounds) a float token.
static int TrReadFloat(TokenReaderT *tr, const double loBound, const double hiBound, double *value)
{
- uint col, digis, len;
- char ch, temp[64+1];
-
- col = tr->mColumn;
+ uint col{tr->mColumn};
if(TrSkipWhitespace(tr))
{
col = tr->mColumn;
- len = 0;
- ch = tr->mRing[tr->mOut&TR_RING_MASK];
+ std::array<char,64+1> temp{};
+ uint len{0};
+ char ch{tr->mRing[tr->mOut&TRRingMask]};
if(ch == '+' || ch == '-')
{
temp[len] = ch;
@@ -456,10 +461,10 @@ static int TrReadFloat(TokenReaderT *tr, const double loBound, const double hiBo
tr->mOut++;
}
- digis = 0;
+ uint digis{0};
while(TrLoad(tr))
{
- ch = tr->mRing[tr->mOut&TR_RING_MASK];
+ ch = tr->mRing[tr->mOut&TRRingMask];
if(!isdigit(ch)) break;
if(len < 64)
temp[len] = ch;
@@ -476,7 +481,7 @@ static int TrReadFloat(TokenReaderT *tr, const double loBound, const double hiBo
}
while(TrLoad(tr))
{
- ch = tr->mRing[tr->mOut&TR_RING_MASK];
+ ch = tr->mRing[tr->mOut&TRRingMask];
if(!isdigit(ch)) break;
if(len < 64)
temp[len] = ch;
@@ -502,7 +507,7 @@ static int TrReadFloat(TokenReaderT *tr, const double loBound, const double hiBo
}
while(TrLoad(tr))
{
- ch = tr->mRing[tr->mOut&TR_RING_MASK];
+ ch = tr->mRing[tr->mOut&TRRingMask];
if(!isdigit(ch)) break;
if(len < 64)
temp[len] = ch;
@@ -520,7 +525,7 @@ static int TrReadFloat(TokenReaderT *tr, const double loBound, const double hiBo
return 0;
}
temp[len] = '\0';
- *value = strtod(temp, nullptr);
+ *value = strtod(temp.data(), nullptr);
if(*value < loBound || *value > hiBound)
{
TrErrorAt(tr, tr->mLine, col, "Expected a value from %f to %f.\n", loBound, hiBound);
@@ -546,14 +551,14 @@ static int TrReadString(TokenReaderT *tr, const uint maxLen, char *text)
if(TrSkipWhitespace(tr))
{
col = tr->mColumn;
- ch = tr->mRing[tr->mOut&TR_RING_MASK];
+ ch = tr->mRing[tr->mOut&TRRingMask];
if(ch == '\"')
{
tr->mOut++;
len = 0;
while(TrLoad(tr))
{
- ch = tr->mRing[tr->mOut&TR_RING_MASK];
+ ch = tr->mRing[tr->mOut&TRRingMask];
tr->mOut++;
if(ch == '\"')
break;
@@ -599,7 +604,7 @@ static int TrReadOperator(TokenReaderT *tr, const char *op)
len = 0;
while(op[len] != '\0' && TrLoad(tr))
{
- ch = tr->mRing[tr->mOut&TR_RING_MASK];
+ ch = tr->mRing[tr->mOut&TRRingMask];
if(ch != op[len]) break;
len++;
tr->mOut++;
@@ -621,8 +626,8 @@ static int TrReadOperator(TokenReaderT *tr, const char *op)
// storing it as a 32-bit unsigned integer.
static int ReadBin4(std::istream &istream, const char *filename, const ByteOrderT order, const uint bytes, uint32_t *out)
{
- uint8_t in[4];
- istream.read(reinterpret_cast<char*>(in), static_cast<int>(bytes));
+ std::array<uint8_t,4> in{};
+ istream.read(reinterpret_cast<char*>(in.data()), static_cast<int>(bytes));
if(istream.gcount() != bytes)
{
fprintf(stderr, "\nError: Bad read from file '%s'.\n", filename);
@@ -650,29 +655,27 @@ static int ReadBin4(std::istream &istream, const char *filename, const ByteOrder
// a 64-bit unsigned integer.
static int ReadBin8(std::istream &istream, const char *filename, const ByteOrderT order, uint64_t *out)
{
- uint8_t in[8];
- uint64_t accum;
- uint i;
-
- istream.read(reinterpret_cast<char*>(in), 8);
+ std::array<uint8_t,8> in{};
+ istream.read(reinterpret_cast<char*>(in.data()), 8);
if(istream.gcount() != 8)
{
fprintf(stderr, "\nError: Bad read from file '%s'.\n", filename);
return 0;
}
- accum = 0;
+
+ uint64_t accum{};
switch(order)
{
- case BO_LITTLE:
- for(i = 0;i < 8;i++)
- accum = (accum<<8) | in[8 - i - 1];
- break;
- case BO_BIG:
- for(i = 0;i < 8;i++)
- accum = (accum<<8) | in[i];
- break;
- default:
- break;
+ case BO_LITTLE:
+ for(uint i{0};i < 8;++i)
+ accum = (accum<<8) | in[8 - i - 1];
+ break;
+ case BO_BIG:
+ for(uint i{0};i < 8;++i)
+ accum = (accum<<8) | in[i];
+ break;
+ default:
+ break;
}
*out = accum;
return 1;
@@ -687,40 +690,32 @@ static int ReadBin8(std::istream &istream, const char *filename, const ByteOrder
static int ReadBinAsDouble(std::istream &istream, const char *filename, const ByteOrderT order,
const ElementTypeT type, const uint bytes, const int bits, double *out)
{
- union {
- uint32_t ui;
- int32_t i;
- float f;
- } v4;
- union {
- uint64_t ui;
- double f;
- } v8;
-
*out = 0.0;
if(bytes > 4)
{
- if(!ReadBin8(istream, filename, order, &v8.ui))
+ uint64_t val{};
+ if(!ReadBin8(istream, filename, order, &val))
return 0;
if(type == ET_FP)
- *out = v8.f;
+ *out = al::bit_cast<double>(val);
}
else
{
- if(!ReadBin4(istream, filename, order, bytes, &v4.ui))
+ uint32_t val{};
+ if(!ReadBin4(istream, filename, order, bytes, &val))
return 0;
if(type == ET_FP)
- *out = v4.f;
+ *out = al::bit_cast<float>(val);
else
{
if(bits > 0)
- v4.ui >>= (8*bytes) - (static_cast<uint>(bits));
+ val >>= (8*bytes) - (static_cast<uint>(bits));
else
- v4.ui &= (0xFFFFFFFF >> (32+bits));
+ val &= (0xFFFFFFFF >> (32+bits));
- if(v4.ui&static_cast<uint>(1<<(std::abs(bits)-1)))
- v4.ui |= (0xFFFFFFFF << std::abs(bits));
- *out = v4.i / static_cast<double>(1<<(std::abs(bits)-1));
+ if(val&static_cast<uint>(1<<(std::abs(bits)-1)))
+ val |= (0xFFFFFFFF << std::abs(bits));
+ *out = static_cast<int32_t>(val) / static_cast<double>(1<<(std::abs(bits)-1));
}
}
return 1;
@@ -776,20 +771,20 @@ static int ReadWaveFormat(std::istream &istream, const ByteOrderT order, const u
do {
if(chunkSize > 0)
istream.seekg(static_cast<int>(chunkSize), std::ios::cur);
- if(!ReadBin4(istream, src->mPath, BO_LITTLE, 4, &fourCC)
- || !ReadBin4(istream, src->mPath, order, 4, &chunkSize))
+ if(!ReadBin4(istream, src->mPath.data(), BO_LITTLE, 4, &fourCC)
+ || !ReadBin4(istream, src->mPath.data(), order, 4, &chunkSize))
return 0;
} while(fourCC != FOURCC_FMT);
- if(!ReadBin4(istream, src->mPath, order, 2, &format)
- || !ReadBin4(istream, src->mPath, order, 2, &channels)
- || !ReadBin4(istream, src->mPath, order, 4, &rate)
- || !ReadBin4(istream, src->mPath, order, 4, &dummy)
- || !ReadBin4(istream, src->mPath, order, 2, &block))
+ if(!ReadBin4(istream, src->mPath.data(), order, 2, &format)
+ || !ReadBin4(istream, src->mPath.data(), order, 2, &channels)
+ || !ReadBin4(istream, src->mPath.data(), order, 4, &rate)
+ || !ReadBin4(istream, src->mPath.data(), order, 4, &dummy)
+ || !ReadBin4(istream, src->mPath.data(), order, 2, &block))
return 0;
block /= channels;
if(chunkSize > 14)
{
- if(!ReadBin4(istream, src->mPath, order, 2, &size))
+ if(!ReadBin4(istream, src->mPath.data(), order, 2, &size))
return 0;
size /= 8;
if(block > size)
@@ -800,12 +795,12 @@ static int ReadWaveFormat(std::istream &istream, const ByteOrderT order, const u
if(format == WAVE_FORMAT_EXTENSIBLE)
{
istream.seekg(2, std::ios::cur);
- if(!ReadBin4(istream, src->mPath, order, 2, &bits))
+ if(!ReadBin4(istream, src->mPath.data(), order, 2, &bits))
return 0;
if(bits == 0)
bits = 8 * size;
istream.seekg(4, std::ios::cur);
- if(!ReadBin4(istream, src->mPath, order, 2, &format))
+ if(!ReadBin4(istream, src->mPath.data(), order, 2, &format))
return 0;
istream.seekg(static_cast<int>(chunkSize - 26), std::ios::cur);
}
@@ -819,29 +814,32 @@ static int ReadWaveFormat(std::istream &istream, const ByteOrderT order, const u
}
if(format != WAVE_FORMAT_PCM && format != WAVE_FORMAT_IEEE_FLOAT)
{
- fprintf(stderr, "\nError: Unsupported WAVE format in file '%s'.\n", src->mPath);
+ fprintf(stderr, "\nError: Unsupported WAVE format in file '%s'.\n", src->mPath.data());
return 0;
}
if(src->mChannel >= channels)
{
- fprintf(stderr, "\nError: Missing source channel in WAVE file '%s'.\n", src->mPath);
+ fprintf(stderr, "\nError: Missing source channel in WAVE file '%s'.\n", src->mPath.data());
return 0;
}
if(rate != hrirRate)
{
- fprintf(stderr, "\nError: Mismatched source sample rate in WAVE file '%s'.\n", src->mPath);
+ fprintf(stderr, "\nError: Mismatched source sample rate in WAVE file '%s'.\n",
+ src->mPath.data());
return 0;
}
if(format == WAVE_FORMAT_PCM)
{
if(size < 2 || size > 4)
{
- fprintf(stderr, "\nError: Unsupported sample size in WAVE file '%s'.\n", src->mPath);
+ fprintf(stderr, "\nError: Unsupported sample size in WAVE file '%s'.\n",
+ src->mPath.data());
return 0;
}
if(bits < 16 || bits > (8*size))
{
- fprintf(stderr, "\nError: Bad significant bits in WAVE file '%s'.\n", src->mPath);
+ fprintf(stderr, "\nError: Bad significant bits in WAVE file '%s'.\n",
+ src->mPath.data());
return 0;
}
src->mType = ET_INT;
@@ -850,7 +848,8 @@ static int ReadWaveFormat(std::istream &istream, const ByteOrderT order, const u
{
if(size != 4 && size != 8)
{
- fprintf(stderr, "\nError: Unsupported sample size in WAVE file '%s'.\n", src->mPath);
+ fprintf(stderr, "\nError: Unsupported sample size in WAVE file '%s'.\n",
+ src->mPath.data());
return 0;
}
src->mType = ET_FP;
@@ -876,7 +875,8 @@ static int ReadWaveData(std::istream &istream, const SourceRefT *src, const Byte
skip += pre;
if(skip > 0)
istream.seekg(skip, std::ios::cur);
- if(!ReadBinAsDouble(istream, src->mPath, order, src->mType, src->mSize, src->mBits, &hrir[i]))
+ if(!ReadBinAsDouble(istream, src->mPath.data(), order, src->mType, src->mSize, src->mBits,
+ &hrir[i]))
return 0;
skip = post;
}
@@ -896,8 +896,8 @@ static int ReadWaveList(std::istream &istream, const SourceRefT *src, const Byte
for(;;)
{
- if(!ReadBin4(istream, src->mPath, BO_LITTLE, 4, &fourCC)
- || !ReadBin4(istream, src->mPath, order, 4, &chunkSize))
+ if(!ReadBin4(istream, src->mPath.data(), BO_LITTLE, 4, &fourCC)
+ || !ReadBin4(istream, src->mPath.data(), order, 4, &chunkSize))
return 0;
if(fourCC == FOURCC_DATA)
@@ -906,17 +906,18 @@ static int ReadWaveList(std::istream &istream, const SourceRefT *src, const Byte
count = chunkSize / block;
if(count < (src->mOffset + n))
{
- fprintf(stderr, "\nError: Bad read from file '%s'.\n", src->mPath);
+ fprintf(stderr, "\nError: Bad read from file '%s'.\n", src->mPath.data());
return 0;
}
- istream.seekg(static_cast<long>(src->mOffset * block), std::ios::cur);
+ using off_type = std::istream::off_type;
+ istream.seekg(off_type(src->mOffset) * off_type(block), std::ios::cur);
if(!ReadWaveData(istream, src, order, n, &hrir[0]))
return 0;
return 1;
}
else if(fourCC == FOURCC_LIST)
{
- if(!ReadBin4(istream, src->mPath, BO_LITTLE, 4, &fourCC))
+ if(!ReadBin4(istream, src->mPath.data(), BO_LITTLE, 4, &fourCC))
return 0;
chunkSize -= 4;
if(fourCC == FOURCC_WAVL)
@@ -932,8 +933,8 @@ static int ReadWaveList(std::istream &istream, const SourceRefT *src, const Byte
lastSample = 0.0;
while(offset < n && listSize > 8)
{
- if(!ReadBin4(istream, src->mPath, BO_LITTLE, 4, &fourCC)
- || !ReadBin4(istream, src->mPath, order, 4, &chunkSize))
+ if(!ReadBin4(istream, src->mPath.data(), BO_LITTLE, 4, &fourCC)
+ || !ReadBin4(istream, src->mPath.data(), order, 4, &chunkSize))
return 0;
listSize -= 8 + chunkSize;
if(fourCC == FOURCC_DATA)
@@ -941,7 +942,8 @@ static int ReadWaveList(std::istream &istream, const SourceRefT *src, const Byte
count = chunkSize / block;
if(count > skip)
{
- istream.seekg(static_cast<long>(skip * block), std::ios::cur);
+ using off_type = std::istream::off_type;
+ istream.seekg(off_type(skip) * off_type(block), std::ios::cur);
chunkSize -= skip * block;
count -= skip;
skip = 0;
@@ -961,7 +963,7 @@ static int ReadWaveList(std::istream &istream, const SourceRefT *src, const Byte
}
else if(fourCC == FOURCC_SLNT)
{
- if(!ReadBin4(istream, src->mPath, order, 4, &count))
+ if(!ReadBin4(istream, src->mPath.data(), order, 4, &count))
return 0;
chunkSize -= 4;
if(count > skip)
@@ -985,7 +987,7 @@ static int ReadWaveList(std::istream &istream, const SourceRefT *src, const Byte
}
if(offset < n)
{
- fprintf(stderr, "\nError: Bad read from file '%s'.\n", src->mPath);
+ fprintf(stderr, "\nError: Bad read from file '%s'.\n", src->mPath.data());
return 0;
}
return 1;
@@ -997,22 +999,25 @@ static int LoadAsciiSource(std::istream &istream, const SourceRefT *src,
const uint n, double *hrir)
{
TokenReaderT tr{istream};
- uint i, j;
- double dummy;
TrSetup(nullptr, 0, nullptr, &tr);
- for(i = 0;i < src->mOffset;i++)
+ for(uint i{0};i < src->mOffset;++i)
{
- if(!ReadAsciiAsDouble(&tr, src->mPath, src->mType, static_cast<uint>(src->mBits), &dummy))
+ double dummy{};
+ if(!ReadAsciiAsDouble(&tr, src->mPath.data(), src->mType, static_cast<uint>(src->mBits),
+ &dummy))
return 0;
}
- for(i = 0;i < n;i++)
+ for(uint i{0};i < n;++i)
{
- if(!ReadAsciiAsDouble(&tr, src->mPath, src->mType, static_cast<uint>(src->mBits), &hrir[i]))
+ if(!ReadAsciiAsDouble(&tr, src->mPath.data(), src->mType, static_cast<uint>(src->mBits),
+ &hrir[i]))
return 0;
- for(j = 0;j < src->mSkip;j++)
+ for(uint j{0};j < src->mSkip;++j)
{
- if(!ReadAsciiAsDouble(&tr, src->mPath, src->mType, static_cast<uint>(src->mBits), &dummy))
+ double dummy{};
+ if(!ReadAsciiAsDouble(&tr, src->mPath.data(), src->mType,
+ static_cast<uint>(src->mBits), &dummy))
return 0;
}
}
@@ -1026,7 +1031,8 @@ static int LoadBinarySource(std::istream &istream, const SourceRefT *src, const
istream.seekg(static_cast<long>(src->mOffset), std::ios::beg);
for(uint i{0};i < n;i++)
{
- if(!ReadBinAsDouble(istream, src->mPath, order, src->mType, src->mSize, src->mBits, &hrir[i]))
+ if(!ReadBinAsDouble(istream, src->mPath.data(), order, src->mType, src->mSize, src->mBits,
+ &hrir[i]))
return 0;
if(src->mSkip > 0)
istream.seekg(static_cast<long>(src->mSkip), std::ios::cur);
@@ -1041,8 +1047,8 @@ static int LoadWaveSource(std::istream &istream, SourceRefT *src, const uint hri
uint32_t fourCC, dummy;
ByteOrderT order;
- if(!ReadBin4(istream, src->mPath, BO_LITTLE, 4, &fourCC)
- || !ReadBin4(istream, src->mPath, BO_LITTLE, 4, &dummy))
+ if(!ReadBin4(istream, src->mPath.data(), BO_LITTLE, 4, &fourCC)
+ || !ReadBin4(istream, src->mPath.data(), BO_LITTLE, 4, &dummy))
return 0;
if(fourCC == FOURCC_RIFF)
order = BO_LITTLE;
@@ -1050,15 +1056,15 @@ static int LoadWaveSource(std::istream &istream, SourceRefT *src, const uint hri
order = BO_BIG;
else
{
- fprintf(stderr, "\nError: No RIFF/RIFX chunk in file '%s'.\n", src->mPath);
+ fprintf(stderr, "\nError: No RIFF/RIFX chunk in file '%s'.\n", src->mPath.data());
return 0;
}
- if(!ReadBin4(istream, src->mPath, BO_LITTLE, 4, &fourCC))
+ if(!ReadBin4(istream, src->mPath.data(), BO_LITTLE, 4, &fourCC))
return 0;
if(fourCC != FOURCC_WAVE)
{
- fprintf(stderr, "\nError: Not a RIFF/RIFX WAVE file '%s'.\n", src->mPath);
+ fprintf(stderr, "\nError: Not a RIFF/RIFX WAVE file '%s'.\n", src->mPath.data());
return 0;
}
if(!ReadWaveFormat(istream, order, hrirRate, src))
@@ -1069,15 +1075,39 @@ static int LoadWaveSource(std::istream &istream, SourceRefT *src, const uint hri
}
+namespace {
+
+struct SofaEasyDeleter {
+ void operator()(gsl::owner<MYSOFA_EASY*> sofa)
+ {
+ if(sofa->neighborhood) mysofa_neighborhood_free(sofa->neighborhood);
+ if(sofa->lookup) mysofa_lookup_free(sofa->lookup);
+ if(sofa->hrtf) mysofa_free(sofa->hrtf);
+ delete sofa;
+ }
+};
+using SofaEasyPtr = std::unique_ptr<MYSOFA_EASY,SofaEasyDeleter>;
+
+struct SofaCacheEntry {
+ std::string mName;
+ uint mSampleRate{};
+ SofaEasyPtr mSofa;
+};
+std::vector<SofaCacheEntry> gSofaCache;
+
+} // namespace
// Load a Spatially Oriented Format for Accoustics (SOFA) file.
static MYSOFA_EASY* LoadSofaFile(SourceRefT *src, const uint hrirRate, const uint n)
{
- struct MYSOFA_EASY *sofa{mysofa_cache_lookup(src->mPath, static_cast<float>(hrirRate))};
- if(sofa) return sofa;
-
- sofa = static_cast<MYSOFA_EASY*>(calloc(1, sizeof(*sofa)));
- if(sofa == nullptr)
+ const std::string_view srcname{src->mPath.data()};
+ auto iter = std::find_if(gSofaCache.begin(), gSofaCache.end(),
+ [srcname,hrirRate](SofaCacheEntry &entry) -> bool
+ { return entry.mName == srcname && entry.mSampleRate == hrirRate; });
+ if(iter != gSofaCache.end()) return iter->mSofa.get();
+
+ SofaEasyPtr sofa{new(std::nothrow) MYSOFA_EASY{}};
+ if(!sofa)
{
fprintf(stderr, "\nError: Out of memory.\n");
return nullptr;
@@ -1086,38 +1116,37 @@ static MYSOFA_EASY* LoadSofaFile(SourceRefT *src, const uint hrirRate, const uin
sofa->neighborhood = nullptr;
int err;
- sofa->hrtf = mysofa_load(src->mPath, &err);
+ sofa->hrtf = mysofa_load(src->mPath.data(), &err);
if(!sofa->hrtf)
{
- mysofa_close(sofa);
- fprintf(stderr, "\nError: Could not load source file '%s'.\n", src->mPath);
+ fprintf(stderr, "\nError: Could not load source file '%s' (error: %d).\n",
+ src->mPath.data(), err);
return nullptr;
}
/* NOTE: Some valid SOFA files are failing this check. */
err = mysofa_check(sofa->hrtf);
if(err != MYSOFA_OK)
- fprintf(stderr, "\nWarning: Supposedly malformed source file '%s'.\n", src->mPath);
+ fprintf(stderr, "\nWarning: Supposedly malformed source file '%s' (error: %d).\n",
+ src->mPath.data(), err);
if((src->mOffset + n) > sofa->hrtf->N)
{
- mysofa_close(sofa);
- fprintf(stderr, "\nError: Not enough samples in SOFA file '%s'.\n", src->mPath);
+ fprintf(stderr, "\nError: Not enough samples in SOFA file '%s'.\n", src->mPath.data());
return nullptr;
}
if(src->mChannel >= sofa->hrtf->R)
{
- mysofa_close(sofa);
- fprintf(stderr, "\nError: Missing source receiver in SOFA file '%s'.\n", src->mPath);
+ fprintf(stderr, "\nError: Missing source receiver in SOFA file '%s'.\n",src->mPath.data());
return nullptr;
}
mysofa_tocartesian(sofa->hrtf);
sofa->lookup = mysofa_lookup_init(sofa->hrtf);
if(sofa->lookup == nullptr)
{
- mysofa_close(sofa);
fprintf(stderr, "\nError: Out of memory.\n");
return nullptr;
}
- return mysofa_cache_store(sofa, src->mPath, static_cast<float>(hrirRate));
+ gSofaCache.emplace_back(SofaCacheEntry{std::string{srcname}, hrirRate, std::move(sofa)});
+ return gSofaCache.back().mSofa.get();
}
// Copies the HRIR data from a particular SOFA measurement.
@@ -1131,40 +1160,39 @@ static void ExtractSofaHrir(const MYSOFA_EASY *sofa, const uint index, const uin
// file.
static int LoadSofaSource(SourceRefT *src, const uint hrirRate, const uint n, double *hrir)
{
- struct MYSOFA_EASY *sofa;
- float target[3];
- int nearest;
- float *coords;
+ MYSOFA_EASY *sofa{LoadSofaFile(src, hrirRate, n)};
+ if(sofa == nullptr) return 0;
- sofa = LoadSofaFile(src, hrirRate, n);
- if(sofa == nullptr)
- return 0;
-
- /* NOTE: At some point it may be benficial or necessary to consider the
+ /* NOTE: At some point it may be beneficial or necessary to consider the
various coordinate systems, listener/source orientations, and
- direciontal vectors defined in the SOFA file.
+ directional vectors defined in the SOFA file.
*/
- target[0] = static_cast<float>(src->mAzimuth);
- target[1] = static_cast<float>(src->mElevation);
- target[2] = static_cast<float>(src->mRadius);
- mysofa_s2c(target);
-
- nearest = mysofa_lookup(sofa->lookup, target);
+ std::array target{
+ static_cast<float>(src->mAzimuth),
+ static_cast<float>(src->mElevation),
+ static_cast<float>(src->mRadius)
+ };
+ mysofa_s2c(target.data());
+
+ int nearest{mysofa_lookup(sofa->lookup, target.data())};
if(nearest < 0)
{
- fprintf(stderr, "\nError: Lookup failed in source file '%s'.\n", src->mPath);
+ fprintf(stderr, "\nError: Lookup failed in source file '%s'.\n", src->mPath.data());
return 0;
}
- coords = &sofa->hrtf->SourcePosition.values[3 * nearest];
- if(std::abs(coords[0] - target[0]) > 0.001 || std::abs(coords[1] - target[1]) > 0.001 || std::abs(coords[2] - target[2]) > 0.001)
+ al::span<float,3> coords{&sofa->hrtf->SourcePosition.values[3_z * nearest], 3};
+ if(std::abs(coords[0] - target[0]) > 0.001 || std::abs(coords[1] - target[1]) > 0.001
+ || std::abs(coords[2] - target[2]) > 0.001)
{
- fprintf(stderr, "\nError: No impulse response at coordinates (%.3fr, %.1fev, %.1faz) in file '%s'.\n", src->mRadius, src->mElevation, src->mAzimuth, src->mPath);
+ fprintf(stderr, "\nError: No impulse response at coordinates (%.3fr, %.1fev, %.1faz) in file '%s'.\n",
+ src->mRadius, src->mElevation, src->mAzimuth, src->mPath.data());
target[0] = coords[0];
target[1] = coords[1];
target[2] = coords[2];
- mysofa_c2s(target);
- fprintf(stderr, " Nearest candidate at (%.3fr, %.1fev, %.1faz).\n", target[2], target[1], target[0]);
+ mysofa_c2s(target.data());
+ fprintf(stderr, " Nearest candidate at (%.3fr, %.1fev, %.1faz).\n", target[2],
+ target[1], target[0]);
return 0;
}
@@ -1180,12 +1208,12 @@ static int LoadSource(SourceRefT *src, const uint hrirRate, const uint n, double
if(src->mFormat != SF_SOFA)
{
if(src->mFormat == SF_ASCII)
- istream.reset(new al::ifstream{src->mPath});
+ istream = std::make_unique<al::ifstream>(src->mPath.data());
else
- istream.reset(new al::ifstream{src->mPath, std::ios::binary});
+ istream = std::make_unique<al::ifstream>(src->mPath.data(), std::ios::binary);
if(!istream->good())
{
- fprintf(stderr, "\nError: Could not open source file '%s'.\n", src->mPath);
+ fprintf(stderr, "\nError: Could not open source file '%s'.\n", src->mPath.data());
return 0;
}
}
@@ -1230,14 +1258,14 @@ static int ProcessMetrics(TokenReaderT *tr, const uint fftSize, const uint trunc
{
int hasRate = 0, hasType = 0, hasPoints = 0, hasRadius = 0;
int hasDistance = 0, hasAzimuths = 0;
- char ident[MAX_IDENT_LEN+1];
+ std::array<char,MaxIdentLen+1> ident;
uint line, col;
double fpVal;
uint points;
int intVal;
- double distances[MAX_FD_COUNT];
+ std::array<double,MAX_FD_COUNT> distances;
uint fdCount = 0;
- uint evCounts[MAX_FD_COUNT];
+ std::array<uint,MAX_FD_COUNT> evCounts;
auto azCounts = std::vector<std::array<uint,MAX_EV_COUNT>>(MAX_FD_COUNT);
for(auto &azs : azCounts) azs.fill(0u);
@@ -1245,9 +1273,9 @@ static int ProcessMetrics(TokenReaderT *tr, const uint fftSize, const uint trunc
while(TrIsIdent(tr))
{
TrIndication(tr, &line, &col);
- if(!TrReadIdent(tr, MAX_IDENT_LEN, ident))
+ if(!TrReadIdent(tr, MaxIdentLen, ident.data()))
return 0;
- if(al::strcasecmp(ident, "rate") == 0)
+ if(al::strcasecmp(ident.data(), "rate") == 0)
{
if(hasRate)
{
@@ -1261,9 +1289,9 @@ static int ProcessMetrics(TokenReaderT *tr, const uint fftSize, const uint trunc
hData->mIrRate = static_cast<uint>(intVal);
hasRate = 1;
}
- else if(al::strcasecmp(ident, "type") == 0)
+ else if(al::strcasecmp(ident.data(), "type") == 0)
{
- char type[MAX_IDENT_LEN+1];
+ std::array<char,MaxIdentLen+1> type;
if(hasType)
{
@@ -1273,9 +1301,9 @@ static int ProcessMetrics(TokenReaderT *tr, const uint fftSize, const uint trunc
if(!TrReadOperator(tr, "="))
return 0;
- if(!TrReadIdent(tr, MAX_IDENT_LEN, type))
+ if(!TrReadIdent(tr, MaxIdentLen, type.data()))
return 0;
- hData->mChannelType = MatchChannelType(type);
+ hData->mChannelType = MatchChannelType(type.data());
if(hData->mChannelType == CT_NONE)
{
TrErrorAt(tr, line, col, "Expected a channel type.\n");
@@ -1288,7 +1316,7 @@ static int ProcessMetrics(TokenReaderT *tr, const uint fftSize, const uint trunc
}
hasType = 1;
}
- else if(al::strcasecmp(ident, "points") == 0)
+ else if(al::strcasecmp(ident.data(), "points") == 0)
{
if(hasPoints)
{
@@ -1318,7 +1346,7 @@ static int ProcessMetrics(TokenReaderT *tr, const uint fftSize, const uint trunc
hData->mIrSize = points;
hasPoints = 1;
}
- else if(al::strcasecmp(ident, "radius") == 0)
+ else if(al::strcasecmp(ident.data(), "radius") == 0)
{
if(hasRadius)
{
@@ -1327,12 +1355,12 @@ static int ProcessMetrics(TokenReaderT *tr, const uint fftSize, const uint trunc
}
if(!TrReadOperator(tr, "="))
return 0;
- if(!TrReadFloat(tr, MIN_RADIUS, MAX_RADIUS, &fpVal))
+ if(!TrReadFloat(tr, MinRadius, MaxRadius, &fpVal))
return 0;
hData->mRadius = fpVal;
hasRadius = 1;
}
- else if(al::strcasecmp(ident, "distance") == 0)
+ else if(al::strcasecmp(ident.data(), "distance") == 0)
{
uint count = 0;
@@ -1371,7 +1399,7 @@ static int ProcessMetrics(TokenReaderT *tr, const uint fftSize, const uint trunc
fdCount = count;
hasDistance = 1;
}
- else if(al::strcasecmp(ident, "azimuths") == 0)
+ else if(al::strcasecmp(ident.data(), "azimuths") == 0)
{
uint count = 0;
@@ -1451,7 +1479,7 @@ static int ProcessMetrics(TokenReaderT *tr, const uint fftSize, const uint trunc
if(hData->mChannelType == CT_NONE)
hData->mChannelType = CT_MONO;
const auto azs = al::span{azCounts}.first<MAX_FD_COUNT>();
- if(!PrepareHrirData({distances, fdCount}, evCounts, azs, hData))
+ if(!PrepareHrirData(al::span{distances}.first(fdCount), evCounts, azs, hData))
{
fprintf(stderr, "Error: Out of memory.\n");
exit(-1);
@@ -1516,15 +1544,15 @@ static ElementTypeT MatchElementType(const char *ident)
// Parse and validate a source reference from the data set definition.
static int ReadSourceRef(TokenReaderT *tr, SourceRefT *src)
{
- char ident[MAX_IDENT_LEN+1];
+ std::array<char,MaxIdentLen+1> ident;
uint line, col;
double fpVal;
int intVal;
TrIndication(tr, &line, &col);
- if(!TrReadIdent(tr, MAX_IDENT_LEN, ident))
+ if(!TrReadIdent(tr, MaxIdentLen, ident.data()))
return 0;
- src->mFormat = MatchSourceFormat(ident);
+ src->mFormat = MatchSourceFormat(ident.data());
if(src->mFormat == SF_NONE)
{
TrErrorAt(tr, line, col, "Expected a source format.\n");
@@ -1549,7 +1577,7 @@ static int ReadSourceRef(TokenReaderT *tr, SourceRefT *src)
src->mAzimuth = fpVal;
if(!TrReadOperator(tr, ":"))
return 0;
- if(!TrReadInt(tr, 0, MAX_WAVE_CHANNELS, &intVal))
+ if(!TrReadInt(tr, 0, MaxWaveChannels, &intVal))
return 0;
src->mType = ET_NONE;
src->mSize = 0;
@@ -1559,7 +1587,7 @@ static int ReadSourceRef(TokenReaderT *tr, SourceRefT *src)
}
else if(src->mFormat == SF_WAVE)
{
- if(!TrReadInt(tr, 0, MAX_WAVE_CHANNELS, &intVal))
+ if(!TrReadInt(tr, 0, MaxWaveChannels, &intVal))
return 0;
src->mType = ET_NONE;
src->mSize = 0;
@@ -1570,9 +1598,9 @@ static int ReadSourceRef(TokenReaderT *tr, SourceRefT *src)
else
{
TrIndication(tr, &line, &col);
- if(!TrReadIdent(tr, MAX_IDENT_LEN, ident))
+ if(!TrReadIdent(tr, MaxIdentLen, ident.data()))
return 0;
- src->mType = MatchElementType(ident);
+ src->mType = MatchElementType(ident.data());
if(src->mType == ET_NONE)
{
TrErrorAt(tr, line, col, "Expected a source element type.\n");
@@ -1584,7 +1612,7 @@ static int ReadSourceRef(TokenReaderT *tr, SourceRefT *src)
return 0;
if(src->mType == ET_INT)
{
- if(!TrReadInt(tr, MIN_BIN_SIZE, MAX_BIN_SIZE, &intVal))
+ if(!TrReadInt(tr, MinBinSize, MaxBinSize, &intVal))
return 0;
src->mSize = static_cast<uint>(intVal);
if(!TrIsOperator(tr, ","))
@@ -1595,9 +1623,9 @@ static int ReadSourceRef(TokenReaderT *tr, SourceRefT *src)
TrIndication(tr, &line, &col);
if(!TrReadInt(tr, -2147483647-1, 2147483647, &intVal))
return 0;
- if(std::abs(intVal) < MIN_BIN_BITS || static_cast<uint>(std::abs(intVal)) > (8*src->mSize))
+ if(std::abs(intVal) < int{MinBinSize}*8 || static_cast<uint>(std::abs(intVal)) > (8*src->mSize))
{
- TrErrorAt(tr, line, col, "Expected a value of (+/-) %d to %d.\n", MIN_BIN_BITS, 8*src->mSize);
+ TrErrorAt(tr, line, col, "Expected a value of (+/-) %d to %d.\n", MinBinSize*8, 8*src->mSize);
return 0;
}
src->mBits = intVal;
@@ -1621,7 +1649,7 @@ static int ReadSourceRef(TokenReaderT *tr, SourceRefT *src)
{
if(!TrReadOperator(tr, ","))
return 0;
- if(!TrReadInt(tr, MIN_ASCII_BITS, MAX_ASCII_BITS, &intVal))
+ if(!TrReadInt(tr, MinASCIIBits, MaxASCIIBits, &intVal))
return 0;
src->mSize = 0;
src->mBits = intVal;
@@ -1655,7 +1683,7 @@ static int ReadSourceRef(TokenReaderT *tr, SourceRefT *src)
src->mOffset = 0;
if(!TrReadOperator(tr, ":"))
return 0;
- if(!TrReadString(tr, MAX_PATH_LEN, src->mPath))
+ if(!TrReadString(tr, MAX_PATH_LEN, src->mPath.data()))
return 0;
return 1;
}
@@ -1663,14 +1691,14 @@ static int ReadSourceRef(TokenReaderT *tr, SourceRefT *src)
// Parse and validate a SOFA source reference from the data set definition.
static int ReadSofaRef(TokenReaderT *tr, SourceRefT *src)
{
- char ident[MAX_IDENT_LEN+1];
+ std::array<char,MaxIdentLen+1> ident;
uint line, col;
int intVal;
TrIndication(tr, &line, &col);
- if(!TrReadIdent(tr, MAX_IDENT_LEN, ident))
+ if(!TrReadIdent(tr, MaxIdentLen, ident.data()))
return 0;
- src->mFormat = MatchSourceFormat(ident);
+ src->mFormat = MatchSourceFormat(ident.data());
if(src->mFormat != SF_SOFA)
{
TrErrorAt(tr, line, col, "Expected the SOFA source format.\n");
@@ -1694,7 +1722,7 @@ static int ReadSofaRef(TokenReaderT *tr, SourceRefT *src)
src->mOffset = 0;
if(!TrReadOperator(tr, ":"))
return 0;
- if(!TrReadString(tr, MAX_PATH_LEN, src->mPath))
+ if(!TrReadString(tr, MAX_PATH_LEN, src->mPath.data()))
return 0;
return 1;
}
@@ -1745,12 +1773,12 @@ static void AverageHrirMagnitude(const uint points, const uint n, const double *
static int ProcessSources(TokenReaderT *tr, HrirDataT *hData, const uint outRate)
{
const uint channels{(hData->mChannelType == CT_STEREO) ? 2u : 1u};
- hData->mHrirsBase.resize(channels * hData->mIrCount * hData->mIrSize);
+ hData->mHrirsBase.resize(size_t{channels} * hData->mIrCount * hData->mIrSize);
double *hrirs = hData->mHrirsBase.data();
- auto hrir = std::make_unique<double[]>(hData->mIrSize);
+ auto hrir = std::vector<double>(hData->mIrSize);
uint line, col, fi, ei, ai;
- std::vector<double> onsetSamples(OnsetRateMultiple * hData->mIrPoints);
+ std::vector<double> onsetSamples(size_t{OnsetRateMultiple} * hData->mIrPoints);
PPhaseResampler onsetResampler;
onsetResampler.init(hData->mIrRate, OnsetRateMultiple*hData->mIrRate);
@@ -1767,57 +1795,50 @@ static int ProcessSources(TokenReaderT *tr, HrirDataT *hData, const uint outRate
int count{0};
while(TrIsOperator(tr, "["))
{
- double factor[2]{ 1.0, 1.0 };
+ std::array factor{1.0, 1.0};
TrIndication(tr, &line, &col);
TrReadOperator(tr, "[");
if(TrIsOperator(tr, "*"))
{
- SourceRefT src;
- struct MYSOFA_EASY *sofa;
- uint si;
-
TrReadOperator(tr, "*");
if(!TrReadOperator(tr, "]") || !TrReadOperator(tr, "="))
return 0;
TrIndication(tr, &line, &col);
+ SourceRefT src{};
if(!ReadSofaRef(tr, &src))
return 0;
if(hData->mChannelType == CT_STEREO)
{
- char type[MAX_IDENT_LEN+1];
- ChannelTypeT channelType;
+ std::array<char,MaxIdentLen+1> type{};
- if(!TrReadIdent(tr, MAX_IDENT_LEN, type))
+ if(!TrReadIdent(tr, MaxIdentLen, type.data()))
return 0;
- channelType = MatchChannelType(type);
-
+ const ChannelTypeT channelType{MatchChannelType(type.data())};
switch(channelType)
{
- case CT_NONE:
- TrErrorAt(tr, line, col, "Expected a channel type.\n");
- return 0;
- case CT_MONO:
- src.mChannel = 0;
- break;
- case CT_STEREO:
- src.mChannel = 1;
- break;
+ case CT_NONE:
+ TrErrorAt(tr, line, col, "Expected a channel type.\n");
+ return 0;
+ case CT_MONO:
+ src.mChannel = 0;
+ break;
+ case CT_STEREO:
+ src.mChannel = 1;
+ break;
}
}
else
{
- char type[MAX_IDENT_LEN+1];
- ChannelTypeT channelType;
-
- if(!TrReadIdent(tr, MAX_IDENT_LEN, type))
+ std::array<char,MaxIdentLen+1> type{};
+ if(!TrReadIdent(tr, MaxIdentLen, type.data()))
return 0;
- channelType = MatchChannelType(type);
+ ChannelTypeT channelType{MatchChannelType(type.data())};
if(channelType != CT_MONO)
{
TrErrorAt(tr, line, col, "Expected a mono channel type.\n");
@@ -1826,20 +1847,20 @@ static int ProcessSources(TokenReaderT *tr, HrirDataT *hData, const uint outRate
src.mChannel = 0;
}
- sofa = LoadSofaFile(&src, hData->mIrRate, hData->mIrPoints);
+ MYSOFA_EASY *sofa{LoadSofaFile(&src, hData->mIrRate, hData->mIrPoints)};
if(!sofa) return 0;
- for(si = 0;si < sofa->hrtf->M;si++)
+ for(uint si{0};si < sofa->hrtf->M;++si)
{
printf("\rLoading sources... %d of %d", si+1, sofa->hrtf->M);
fflush(stdout);
- float aer[3] = {
- sofa->hrtf->SourcePosition.values[3*si],
- sofa->hrtf->SourcePosition.values[3*si + 1],
- sofa->hrtf->SourcePosition.values[3*si + 2]
+ std::array aer{
+ sofa->hrtf->SourcePosition.values[3_uz*si],
+ sofa->hrtf->SourcePosition.values[3_uz*si + 1],
+ sofa->hrtf->SourcePosition.values[3_uz*si + 2]
};
- mysofa_c2s(aer);
+ mysofa_c2s(aer.data());
if(std::fabs(aer[1]) >= 89.999f)
aer[0] = 0.0f;
@@ -1875,24 +1896,25 @@ static int ProcessSources(TokenReaderT *tr, HrirDataT *hData, const uint outRate
return 0;
}
- ExtractSofaHrir(sofa, si, 0, src.mOffset, hData->mIrPoints, hrir.get());
- azd->mIrs[0] = &hrirs[hData->mIrSize * azd->mIndex];
+ ExtractSofaHrir(sofa, si, 0, src.mOffset, hData->mIrPoints, hrir.data());
+ azd->mIrs[0] = &hrirs[size_t{hData->mIrSize} * azd->mIndex];
azd->mDelays[0] = AverageHrirOnset(onsetResampler, onsetSamples, hData->mIrRate,
- hData->mIrPoints, hrir.get(), 1.0, azd->mDelays[0]);
+ hData->mIrPoints, hrir.data(), 1.0, azd->mDelays[0]);
if(resampler)
- resampler->process(hData->mIrPoints, hrir.get(), hData->mIrSize, hrir.get());
- AverageHrirMagnitude(irPoints, hData->mFftSize, hrir.get(), 1.0, azd->mIrs[0]);
+ resampler->process(hData->mIrPoints, hrir.data(), hData->mIrSize, hrir.data());
+ AverageHrirMagnitude(irPoints, hData->mFftSize, hrir.data(), 1.0, azd->mIrs[0]);
if(src.mChannel == 1)
{
- ExtractSofaHrir(sofa, si, 1, src.mOffset, hData->mIrPoints, hrir.get());
- azd->mIrs[1] = &hrirs[hData->mIrSize * (hData->mIrCount + azd->mIndex)];
+ ExtractSofaHrir(sofa, si, 1, src.mOffset, hData->mIrPoints, hrir.data());
+ azd->mIrs[1] = &hrirs[hData->mIrSize * (size_t{hData->mIrCount}+azd->mIndex)];
azd->mDelays[1] = AverageHrirOnset(onsetResampler, onsetSamples,
- hData->mIrRate, hData->mIrPoints, hrir.get(), 1.0, azd->mDelays[1]);
+ hData->mIrRate, hData->mIrPoints, hrir.data(), 1.0, azd->mDelays[1]);
if(resampler)
- resampler->process(hData->mIrPoints, hrir.get(), hData->mIrSize,
- hrir.get());
- AverageHrirMagnitude(irPoints, hData->mFftSize, hrir.get(), 1.0, azd->mIrs[1]);
+ resampler->process(hData->mIrPoints, hrir.data(), hData->mIrSize,
+ hrir.data());
+ AverageHrirMagnitude(irPoints, hData->mFftSize, hrir.data(), 1.0,
+ azd->mIrs[1]);
}
// TODO: Since some SOFA files contain minimum phase HRIRs,
@@ -1917,10 +1939,9 @@ static int ProcessSources(TokenReaderT *tr, HrirDataT *hData, const uint outRate
if(!TrReadOperator(tr, "="))
return 0;
- for(;;)
+ while(true)
{
- SourceRefT src;
-
+ SourceRefT src{};
if(!ReadSourceRef(tr, &src))
return 0;
@@ -1931,29 +1952,28 @@ static int ProcessSources(TokenReaderT *tr, HrirDataT *hData, const uint outRate
printf("\rLoading sources... %d file%s", count, (count==1)?"":"s");
fflush(stdout);
- if(!LoadSource(&src, hData->mIrRate, hData->mIrPoints, hrir.get()))
+ if(!LoadSource(&src, hData->mIrRate, hData->mIrPoints, hrir.data()))
return 0;
uint ti{0};
if(hData->mChannelType == CT_STEREO)
{
- char ident[MAX_IDENT_LEN+1];
-
- if(!TrReadIdent(tr, MAX_IDENT_LEN, ident))
+ std::array<char,MaxIdentLen+1> ident{};
+ if(!TrReadIdent(tr, MaxIdentLen, ident.data()))
return 0;
- ti = static_cast<uint>(MatchTargetEar(ident));
+ ti = static_cast<uint>(MatchTargetEar(ident.data()));
if(static_cast<int>(ti) < 0)
{
TrErrorAt(tr, line, col, "Expected a target ear.\n");
return 0;
}
}
- azd->mIrs[ti] = &hrirs[hData->mIrSize * (ti * hData->mIrCount + azd->mIndex)];
+ azd->mIrs[ti] = &hrirs[hData->mIrSize * (ti*size_t{hData->mIrCount} + azd->mIndex)];
azd->mDelays[ti] = AverageHrirOnset(onsetResampler, onsetSamples, hData->mIrRate,
- hData->mIrPoints, hrir.get(), 1.0 / factor[ti], azd->mDelays[ti]);
+ hData->mIrPoints, hrir.data(), 1.0 / factor[ti], azd->mDelays[ti]);
if(resampler)
- resampler->process(hData->mIrPoints, hrir.get(), hData->mIrSize, hrir.get());
- AverageHrirMagnitude(irPoints, hData->mFftSize, hrir.get(), 1.0 / factor[ti],
+ resampler->process(hData->mIrPoints, hrir.data(), hData->mIrSize, hrir.data());
+ AverageHrirMagnitude(irPoints, hData->mFftSize, hrir.data(), 1.0 / factor[ti],
azd->mIrs[ti]);
factor[ti] += 1.0;
if(!TrIsOperator(tr, "+"))
@@ -1975,7 +1995,7 @@ static int ProcessSources(TokenReaderT *tr, HrirDataT *hData, const uint outRate
}
}
printf("\n");
- hrir = nullptr;
+ hrir.clear();
if(resampler)
{
hData->mIrRate = outRate;
@@ -2025,19 +2045,19 @@ static int ProcessSources(TokenReaderT *tr, HrirDataT *hData, const uint outRate
{
HrirAzT *azd = &hData->mFds[fi].mEvs[ei].mAzs[ai];
- azd->mIrs[ti] = &hrirs[hData->mIrSize * (ti * hData->mIrCount + azd->mIndex)];
+ azd->mIrs[ti] = &hrirs[hData->mIrSize * (ti*size_t{hData->mIrCount} + azd->mIndex)];
}
}
}
}
if(!TrLoad(tr))
{
- mysofa_cache_release_all();
+ gSofaCache.clear();
return 1;
}
TrError(tr, "Errant data at end of source list.\n");
- mysofa_cache_release_all();
+ gSofaCache.clear();
return 0;
}
diff --git a/utils/makemhr/loadsofa.cpp b/utils/makemhr/loadsofa.cpp
index 9bcfc38d..b2038c77 100644
--- a/utils/makemhr/loadsofa.cpp
+++ b/utils/makemhr/loadsofa.cpp
@@ -39,6 +39,7 @@
#include <vector>
#include "alspan.h"
+#include "alnumeric.h"
#include "makemhr.h"
#include "polyphase_resampler.h"
#include "sofa-support.h"
@@ -65,8 +66,8 @@ static bool PrepareLayout(const uint m, const float *xyzs, HrirDataT *hData)
return false;
}
- double distances[MAX_FD_COUNT]{};
- uint evCounts[MAX_FD_COUNT]{};
+ std::array<double,MAX_FD_COUNT> distances{};
+ std::array<uint,MAX_FD_COUNT> evCounts{};
auto azCounts = std::vector<std::array<uint,MAX_EV_COUNT>>(MAX_FD_COUNT);
for(auto &azs : azCounts) azs.fill(0u);
@@ -88,7 +89,7 @@ static bool PrepareLayout(const uint m, const float *xyzs, HrirDataT *hData)
}
fprintf(stdout, "Using %u of %u IRs.\n", ir_total, m);
const auto azs = al::span{azCounts}.first<MAX_FD_COUNT>();
- return PrepareHrirData({distances, fi}, evCounts, azs, hData);
+ return PrepareHrirData(al::span{distances}.first(fi), evCounts, azs, hData);
}
@@ -144,7 +145,7 @@ float GetSampleRate(MYSOFA_HRTF *sofaHrtf)
return 0.0f;
}
/* I dimensions guarantees 1 element, so just extract it. */
- if(srate_array->values[0] < MIN_RATE || srate_array->values[0] > MAX_RATE)
+ if(srate_array->values[0] < float{MIN_RATE} || srate_array->values[0] > float{MAX_RATE})
{
fprintf(stderr, "Sample rate out of range: %f (expected %u to %u)", srate_array->values[0],
MIN_RATE, MAX_RATE);
@@ -261,27 +262,27 @@ static bool LoadResponses(MYSOFA_HRTF *sofaHrtf, HrirDataT *hData, const DelayTy
auto load_proc = [sofaHrtf,hData,delayType,outRate,&loaded_count]() -> bool
{
const uint channels{(hData->mChannelType == CT_STEREO) ? 2u : 1u};
- hData->mHrirsBase.resize(channels * hData->mIrCount * hData->mIrSize, 0.0);
+ hData->mHrirsBase.resize(channels * size_t{hData->mIrCount} * hData->mIrSize, 0.0);
double *hrirs = hData->mHrirsBase.data();
- std::unique_ptr<double[]> restmp;
+ std::vector<double> restmp;
std::optional<PPhaseResampler> resampler;
if(outRate && outRate != hData->mIrRate)
{
resampler.emplace().init(hData->mIrRate, outRate);
- restmp = std::make_unique<double[]>(sofaHrtf->N);
+ restmp.resize(sofaHrtf->N);
}
for(uint si{0u};si < sofaHrtf->M;++si)
{
loaded_count.fetch_add(1u);
- float aer[3]{
- sofaHrtf->SourcePosition.values[3*si],
- sofaHrtf->SourcePosition.values[3*si + 1],
- sofaHrtf->SourcePosition.values[3*si + 2]
+ std::array aer{
+ sofaHrtf->SourcePosition.values[3_uz*si],
+ sofaHrtf->SourcePosition.values[3_uz*si + 1],
+ sofaHrtf->SourcePosition.values[3_uz*si + 2]
};
- mysofa_c2s(aer);
+ mysofa_c2s(aer.data());
if(std::abs(aer[1]) >= 89.999f)
aer[0] = 0.0f;
@@ -317,15 +318,15 @@ static bool LoadResponses(MYSOFA_HRTF *sofaHrtf, HrirDataT *hData, const DelayTy
for(uint ti{0u};ti < channels;++ti)
{
- azd->mIrs[ti] = &hrirs[hData->mIrSize * (hData->mIrCount*ti + azd->mIndex)];
+ azd->mIrs[ti] = &hrirs[(size_t{hData->mIrCount}*ti + azd->mIndex)*hData->mIrSize];
if(!resampler)
- std::copy_n(&sofaHrtf->DataIR.values[(si*sofaHrtf->R + ti)*sofaHrtf->N],
+ std::copy_n(&sofaHrtf->DataIR.values[(size_t{si}*sofaHrtf->R + ti)*sofaHrtf->N],
sofaHrtf->N, azd->mIrs[ti]);
else
{
- std::copy_n(&sofaHrtf->DataIR.values[(si*sofaHrtf->R + ti)*sofaHrtf->N],
- sofaHrtf->N, restmp.get());
- resampler->process(sofaHrtf->N, restmp.get(), hData->mIrSize, azd->mIrs[ti]);
+ std::copy_n(&sofaHrtf->DataIR.values[(size_t{si}*sofaHrtf->R + ti)*sofaHrtf->N],
+ sofaHrtf->N, restmp.data());
+ resampler->process(sofaHrtf->N, restmp.data(), hData->mIrSize, azd->mIrs[ti]);
}
}
@@ -382,7 +383,7 @@ struct MagCalculator {
{
auto htemp = std::vector<complex_d>(mFftSize);
- while(1)
+ while(true)
{
/* Load the current index to process. */
size_t idx{mCurrent.load()};
@@ -459,7 +460,7 @@ bool LoadSofaFile(const char *filename, const uint numThreads, const uint fftSiz
/* Assume a default head radius of 9cm. */
hData->mRadius = 0.09;
- hData->mIrRate = static_cast<uint>(GetSampleRate(sofaHrtf.get()) + 0.5f);
+ hData->mIrRate = static_cast<uint>(std::lround(GetSampleRate(sofaHrtf.get())));
if(!hData->mIrRate)
return false;
@@ -520,7 +521,7 @@ bool LoadSofaFile(const char *filename, const uint numThreads, const uint fftSiz
for(uint ai{0u};ai < hData->mFds[fi].mEvs[ei].mAzs.size();ai++)
{
HrirAzT &azd = hData->mFds[fi].mEvs[ei].mAzs[ai];
- for(uint ti{0u};ti < channels;ti++)
+ for(size_t ti{0u};ti < channels;ti++)
azd.mIrs[ti] = &hrirs[hData->mIrSize * (hData->mIrCount*ti + azd.mIndex)];
}
}
@@ -533,7 +534,7 @@ bool LoadSofaFile(const char *filename, const uint numThreads, const uint fftSiz
auto onset_proc = [hData,channels,&hrir_done]() -> bool
{
/* Temporary buffer used to calculate the IR's onset. */
- auto upsampled = std::vector<double>(OnsetRateMultiple * hData->mIrPoints);
+ auto upsampled = std::vector<double>(size_t{OnsetRateMultiple} * hData->mIrPoints);
/* This resampler is used to help detect the response onset. */
PPhaseResampler rs;
rs.init(hData->mIrRate, OnsetRateMultiple*hData->mIrRate);
diff --git a/utils/makemhr/makemhr.cpp b/utils/makemhr/makemhr.cpp
index 98e1b73f..0a9b71e7 100644
--- a/utils/makemhr/makemhr.cpp
+++ b/utils/makemhr/makemhr.cpp
@@ -90,6 +90,8 @@
#include "alcomplex.h"
#include "alfstream.h"
+#include "alnumbers.h"
+#include "alnumeric.h"
#include "alspan.h"
#include "alstring.h"
#include "loaddef.h"
@@ -98,61 +100,61 @@
#include "win_main_utf8.h"
-namespace {
-
-using namespace std::placeholders;
-
-} // namespace
-
-#ifndef M_PI
-#define M_PI (3.14159265358979323846)
-#endif
-
-
HrirDataT::~HrirDataT() = default;
-// Head model used for calculating the impulse delays.
-enum HeadModelT {
- HM_NONE,
- HM_DATASET, // Measure the onset from the dataset.
- HM_SPHERE // Calculate the onset using a spherical head model.
+namespace {
+
+struct FileDeleter {
+ void operator()(gsl::owner<FILE*> f) { fclose(f); }
};
+using FilePtr = std::unique_ptr<FILE,FileDeleter>;
+using namespace std::placeholders;
// The epsilon used to maintain signal stability.
-#define EPSILON (1e-9)
+constexpr double Epsilon{1e-9};
// The limits to the FFT window size override on the command line.
-#define MIN_FFTSIZE (65536)
-#define MAX_FFTSIZE (131072)
+constexpr uint MinFftSize{65536};
+constexpr uint MaxFftSize{131072};
// The limits to the equalization range limit on the command line.
-#define MIN_LIMIT (2.0)
-#define MAX_LIMIT (120.0)
+constexpr double MinLimit{2.0};
+constexpr double MaxLimit{120.0};
// The limits to the truncation window size on the command line.
-#define MIN_TRUNCSIZE (16)
-#define MAX_TRUNCSIZE (128)
+constexpr uint MinTruncSize{16};
+constexpr uint MaxTruncSize{128};
// The limits to the custom head radius on the command line.
-#define MIN_CUSTOM_RADIUS (0.05)
-#define MAX_CUSTOM_RADIUS (0.15)
-
-// The defaults for the command line options.
-#define DEFAULT_FFTSIZE (65536)
-#define DEFAULT_EQUALIZE (1)
-#define DEFAULT_SURFACE (1)
-#define DEFAULT_LIMIT (24.0)
-#define DEFAULT_TRUNCSIZE (64)
-#define DEFAULT_HEAD_MODEL (HM_DATASET)
-#define DEFAULT_CUSTOM_RADIUS (0.0)
+constexpr double MinCustomRadius{0.05};
+constexpr double MaxCustomRadius{0.15};
// The maximum propagation delay value supported by OpenAL Soft.
-#define MAX_HRTD (63.0)
+constexpr double MaxHrtd{63.0};
// The OpenAL Soft HRTF format marker. It stands for minimum-phase head
// response protocol 03.
-#define MHR_FORMAT ("MinPHR03")
+constexpr char MHRFormat[] = "MinPHR03"; // NOLINT(*-avoid-c-arrays)
+
+
+// Head model used for calculating the impulse delays.
+enum HeadModelT {
+ HM_NONE,
+ HM_DATASET, // Measure the onset from the dataset.
+ HM_SPHERE, // Calculate the onset using a spherical head model.
+
+ DEFAULT_HEAD_MODEL = HM_DATASET
+};
+
+
+// The defaults for the command line options.
+constexpr uint DefaultFftSize{65536};
+constexpr bool DefaultEqualize{true};
+constexpr bool DefaultSurface{true};
+constexpr double DefaultLimit{24.0};
+constexpr uint DefaultTruncSize{64};
+constexpr double DefaultCustomRadius{0.0};
/* Channel index enums. Mono uses LeftChannel only. */
enum ChannelIndex : uint {
@@ -165,7 +167,7 @@ enum ChannelIndex : uint {
* pattern string are replaced with the replacement string. The result is
* truncated if necessary.
*/
-static std::string StrSubst(al::span<const char> in, const al::span<const char> pat,
+std::string StrSubst(al::span<const char> in, const al::span<const char> pat,
const al::span<const char> rep)
{
std::string ret;
@@ -198,12 +200,12 @@ static std::string StrSubst(al::span<const char> in, const al::span<const char>
*********************/
// Simple clamp routine.
-static double Clamp(const double val, const double lower, const double upper)
+double Clamp(const double val, const double lower, const double upper)
{
return std::min(std::max(val, lower), upper);
}
-static inline uint dither_rng(uint *seed)
+inline uint dither_rng(uint *seed)
{
*seed = *seed * 96314165 + 907633515;
return *seed;
@@ -211,8 +213,8 @@ static inline uint dither_rng(uint *seed)
// Performs a triangular probability density function dither. The input samples
// should be normalized (-1 to +1).
-static void TpdfDither(double *RESTRICT out, const double *RESTRICT in, const double scale,
- const uint count, const uint step, uint *seed)
+void TpdfDither(double *RESTRICT out, const double *RESTRICT in, const double scale,
+ const uint count, const uint step, uint *seed)
{
static constexpr double PRNG_SCALE = 1.0 / std::numeric_limits<uint>::max();
@@ -231,9 +233,11 @@ static void TpdfDither(double *RESTRICT out, const double *RESTRICT in, const do
* of a signal's magnitude response, the imaginary components can be used as
* the angles for minimum-phase reconstruction.
*/
-inline static void Hilbert(const uint n, complex_d *inout)
+inline void Hilbert(const uint n, complex_d *inout)
{ complex_hilbert({inout, n}); }
+} // namespace
+
/* Calculate the magnitude response of the given input. This is used in
* place of phase decomposition, since the phase residuals are discarded for
* minimum phase reconstruction. The mirrored half of the response is also
@@ -244,7 +248,7 @@ void MagnitudeResponse(const uint n, const complex_d *in, double *out)
const uint m = 1 + (n / 2);
uint i;
for(i = 0;i < m;i++)
- out[i] = std::max(std::abs(in[i]), EPSILON);
+ out[i] = std::max(std::abs(in[i]), Epsilon);
}
/* Apply a range limit (in dB) to the given magnitude response. This is used
@@ -295,7 +299,7 @@ static void MinimumPhase(const uint n, double *mags, complex_d *out)
}
Hilbert(n, out);
// Remove any DC offset the filter has.
- mags[0] = EPSILON;
+ mags[0] = Epsilon;
for(i = 0;i < n;i++)
out[i] = std::polar(mags[i], out[i].imag());
}
@@ -313,7 +317,6 @@ static int WriteAscii(const char *out, FILE *fp, const char *filename)
len = strlen(out);
if(fwrite(out, 1, len, fp) != len)
{
- fclose(fp);
fprintf(stderr, "\nError: Bad write to file '%s'.\n", filename);
return 0;
}
@@ -324,13 +327,11 @@ static int WriteAscii(const char *out, FILE *fp, const char *filename)
// loading it from a 32-bit unsigned integer.
static int WriteBin4(const uint bytes, const uint32_t in, FILE *fp, const char *filename)
{
- uint8_t out[4];
- uint i;
-
- for(i = 0;i < bytes;i++)
+ std::array<uint8_t,4> out{};
+ for(uint i{0};i < bytes;i++)
out[i] = (in>>(i*8)) & 0x000000FF;
- if(fwrite(out, 1, bytes, fp) != bytes)
+ if(fwrite(out.data(), 1, bytes, fp) != bytes)
{
fprintf(stderr, "\nError: Bad write to file '%s'.\n", filename);
return 0;
@@ -345,34 +346,34 @@ static int StoreMhr(const HrirDataT *hData, const char *filename)
const uint n{hData->mIrPoints};
uint dither_seed{22222};
uint fi, ei, ai, i;
- FILE *fp;
- if((fp=fopen(filename, "wb")) == nullptr)
+ FilePtr fp{fopen(filename, "wb")};
+ if(!fp)
{
fprintf(stderr, "\nError: Could not open MHR file '%s'.\n", filename);
return 0;
}
- if(!WriteAscii(MHR_FORMAT, fp, filename))
+ if(!WriteAscii(MHRFormat, fp.get(), filename))
return 0;
- if(!WriteBin4(4, hData->mIrRate, fp, filename))
+ if(!WriteBin4(4, hData->mIrRate, fp.get(), filename))
return 0;
- if(!WriteBin4(1, static_cast<uint32_t>(hData->mChannelType), fp, filename))
+ if(!WriteBin4(1, static_cast<uint32_t>(hData->mChannelType), fp.get(), filename))
return 0;
- if(!WriteBin4(1, hData->mIrPoints, fp, filename))
+ if(!WriteBin4(1, hData->mIrPoints, fp.get(), filename))
return 0;
- if(!WriteBin4(1, static_cast<uint>(hData->mFds.size()), fp, filename))
+ if(!WriteBin4(1, static_cast<uint>(hData->mFds.size()), fp.get(), filename))
return 0;
for(fi = static_cast<uint>(hData->mFds.size()-1);fi < hData->mFds.size();fi--)
{
auto fdist = static_cast<uint32_t>(std::round(1000.0 * hData->mFds[fi].mDistance));
- if(!WriteBin4(2, fdist, fp, filename))
+ if(!WriteBin4(2, fdist, fp.get(), filename))
return 0;
- if(!WriteBin4(1, static_cast<uint32_t>(hData->mFds[fi].mEvs.size()), fp, filename))
+ if(!WriteBin4(1, static_cast<uint32_t>(hData->mFds[fi].mEvs.size()), fp.get(), filename))
return 0;
for(ei = 0;ei < hData->mFds[fi].mEvs.size();ei++)
{
const auto &elev = hData->mFds[fi].mEvs[ei];
- if(!WriteBin4(1, static_cast<uint32_t>(elev.mAzs.size()), fp, filename))
+ if(!WriteBin4(1, static_cast<uint32_t>(elev.mAzs.size()), fp.get(), filename))
return 0;
}
}
@@ -387,15 +388,15 @@ static int StoreMhr(const HrirDataT *hData, const char *filename)
for(ai = 0;ai < hData->mFds[fi].mEvs[ei].mAzs.size();ai++)
{
HrirAzT *azd = &hData->mFds[fi].mEvs[ei].mAzs[ai];
- double out[2 * MAX_TRUNCSIZE];
+ std::array<double,MaxTruncSize*2_uz> out{};
- TpdfDither(out, azd->mIrs[0], scale, n, channels, &dither_seed);
+ TpdfDither(out.data(), azd->mIrs[0], scale, n, channels, &dither_seed);
if(hData->mChannelType == CT_STEREO)
- TpdfDither(out+1, azd->mIrs[1], scale, n, channels, &dither_seed);
+ TpdfDither(out.data()+1, azd->mIrs[1], scale, n, channels, &dither_seed);
for(i = 0;i < (channels * n);i++)
{
const auto v = static_cast<int>(Clamp(out[i], -scale-1.0, scale));
- if(!WriteBin4(bps, static_cast<uint32_t>(v), fp, filename))
+ if(!WriteBin4(bps, static_cast<uint32_t>(v), fp.get(), filename))
return 0;
}
}
@@ -410,16 +411,15 @@ static int StoreMhr(const HrirDataT *hData, const char *filename)
for(const auto &azd : hData->mFds[fi].mEvs[ei].mAzs)
{
auto v = static_cast<uint>(std::round(azd.mDelays[0]*DelayPrecScale));
- if(!WriteBin4(1, v, fp, filename)) return 0;
+ if(!WriteBin4(1, v, fp.get(), filename)) return 0;
if(hData->mChannelType == CT_STEREO)
{
v = static_cast<uint>(std::round(azd.mDelays[1]*DelayPrecScale));
- if(!WriteBin4(1, v, fp, filename)) return 0;
+ if(!WriteBin4(1, v, fp.get(), filename)) return 0;
}
}
}
}
- fclose(fp);
return 1;
}
@@ -434,21 +434,18 @@ static int StoreMhr(const HrirDataT *hData, const char *filename)
*/
static void BalanceFieldMagnitudes(const HrirDataT *hData, const uint channels, const uint m)
{
- double maxMags[MAX_FD_COUNT];
- uint fi, ei, ti, i;
-
+ std::array<double,MAX_FD_COUNT> maxMags{};
double maxMag{0.0};
- for(fi = 0;fi < hData->mFds.size();fi++)
- {
- maxMags[fi] = 0.0;
- for(ei = hData->mFds[fi].mEvStart;ei < hData->mFds[fi].mEvs.size();ei++)
+ for(size_t fi{0};fi < hData->mFds.size();++fi)
+ {
+ for(size_t ei{hData->mFds[fi].mEvStart};ei < hData->mFds[fi].mEvs.size();++ei)
{
for(const auto &azd : hData->mFds[fi].mEvs[ei].mAzs)
{
- for(ti = 0;ti < channels;ti++)
+ for(size_t ti{0};ti < channels;++ti)
{
- for(i = 0;i < m;i++)
+ for(size_t i{0};i < m;++i)
maxMags[fi] = std::max(azd.mIrs[ti][i], maxMags[fi]);
}
}
@@ -457,17 +454,17 @@ static void BalanceFieldMagnitudes(const HrirDataT *hData, const uint channels,
maxMag = std::max(maxMags[fi], maxMag);
}
- for(fi = 0;fi < hData->mFds.size();fi++)
+ for(size_t fi{0};fi < hData->mFds.size();++fi)
{
const double magFactor{maxMag / maxMags[fi]};
- for(ei = hData->mFds[fi].mEvStart;ei < hData->mFds[fi].mEvs.size();ei++)
+ for(size_t ei{hData->mFds[fi].mEvStart};ei < hData->mFds[fi].mEvs.size();++ei)
{
for(const auto &azd : hData->mFds[fi].mEvs[ei].mAzs)
{
- for(ti = 0;ti < channels;ti++)
+ for(size_t ti{0};ti < channels;++ti)
{
- for(i = 0;i < m;i++)
+ for(size_t i{0};i < m;++i)
azd.mIrs[ti][i] *= magFactor;
}
}
@@ -499,17 +496,17 @@ static void CalculateDfWeights(const HrirDataT *hData, double *weights)
outerRa = 10.0f;
const double raPowDiff{std::pow(outerRa, 3.0) - std::pow(innerRa, 3.0)};
- evs = M_PI / 2.0 / static_cast<double>(hData->mFds[fi].mEvs.size() - 1);
+ evs = al::numbers::pi / 2.0 / static_cast<double>(hData->mFds[fi].mEvs.size() - 1);
for(ei = hData->mFds[fi].mEvStart;ei < hData->mFds[fi].mEvs.size();ei++)
{
const auto &elev = hData->mFds[fi].mEvs[ei];
// For each elevation, calculate the upper and lower limits of
// the patch band.
ev = elev.mElevation;
- lowerEv = std::max(-M_PI / 2.0, ev - evs);
- upperEv = std::min(M_PI / 2.0, ev + evs);
+ lowerEv = std::max(-al::numbers::pi / 2.0, ev - evs);
+ upperEv = std::min(al::numbers::pi / 2.0, ev + evs);
// Calculate the surface area of the patch band.
- solidAngle = 2.0 * M_PI * (std::sin(upperEv) - std::sin(lowerEv));
+ solidAngle = 2.0 * al::numbers::pi * (std::sin(upperEv) - std::sin(lowerEv));
// Then the volume of the extruded patch band.
solidVolume = solidAngle * raPowDiff / 3.0;
// Each weight is the volume of one extruded patch.
@@ -539,7 +536,7 @@ static void CalculateDiffuseFieldAverage(const HrirDataT *hData, const uint chan
const int weighted, const double limit, double *dfa)
{
std::vector<double> weights(hData->mFds.size() * MAX_EV_COUNT);
- uint count, ti, fi, ei, i, ai;
+ uint count;
if(weighted)
{
@@ -553,42 +550,42 @@ static void CalculateDiffuseFieldAverage(const HrirDataT *hData, const uint chan
// If coverage weighting is not used, the weights still need to be
// averaged by the number of existing HRIRs.
count = hData->mIrCount;
- for(fi = 0;fi < hData->mFds.size();fi++)
+ for(size_t fi{0};fi < hData->mFds.size();++fi)
{
- for(ei = 0;ei < hData->mFds[fi].mEvStart;ei++)
+ for(size_t ei{0};ei < hData->mFds[fi].mEvStart;++ei)
count -= static_cast<uint>(hData->mFds[fi].mEvs[ei].mAzs.size());
}
weight = 1.0 / count;
- for(fi = 0;fi < hData->mFds.size();fi++)
+ for(size_t fi{0};fi < hData->mFds.size();++fi)
{
- for(ei = hData->mFds[fi].mEvStart;ei < hData->mFds[fi].mEvs.size();ei++)
+ for(size_t ei{hData->mFds[fi].mEvStart};ei < hData->mFds[fi].mEvs.size();++ei)
weights[(fi * MAX_EV_COUNT) + ei] = weight;
}
}
- for(ti = 0;ti < channels;ti++)
+ for(size_t ti{0};ti < channels;++ti)
{
- for(i = 0;i < m;i++)
+ for(size_t i{0};i < m;++i)
dfa[(ti * m) + i] = 0.0;
- for(fi = 0;fi < hData->mFds.size();fi++)
+ for(size_t fi{0};fi < hData->mFds.size();++fi)
{
- for(ei = hData->mFds[fi].mEvStart;ei < hData->mFds[fi].mEvs.size();ei++)
+ for(size_t ei{hData->mFds[fi].mEvStart};ei < hData->mFds[fi].mEvs.size();++ei)
{
- for(ai = 0;ai < hData->mFds[fi].mEvs[ei].mAzs.size();ai++)
+ for(size_t ai{0};ai < hData->mFds[fi].mEvs[ei].mAzs.size();++ai)
{
HrirAzT *azd = &hData->mFds[fi].mEvs[ei].mAzs[ai];
// Get the weight for this HRIR's contribution.
double weight = weights[(fi * MAX_EV_COUNT) + ei];
// Add this HRIR's weighted power average to the total.
- for(i = 0;i < m;i++)
+ for(size_t i{0};i < m;++i)
dfa[(ti * m) + i] += weight * azd->mIrs[ti][i] * azd->mIrs[ti][i];
}
}
}
// Finish the average calculation and keep it from being too small.
- for(i = 0;i < m;i++)
- dfa[(ti * m) + i] = std::max(sqrt(dfa[(ti * m) + i]), EPSILON);
+ for(size_t i{0};i < m;++i)
+ dfa[(ti * m) + i] = std::max(sqrt(dfa[(ti * m) + i]), Epsilon);
// Apply a limit to the magnitude range of the diffuse-field average
// if desired.
if(limit > 0.0)
@@ -600,17 +597,15 @@ static void CalculateDiffuseFieldAverage(const HrirDataT *hData, const uint chan
// set using the given average response.
static void DiffuseFieldEqualize(const uint channels, const uint m, const double *dfa, const HrirDataT *hData)
{
- uint ti, fi, ei, i;
-
- for(fi = 0;fi < hData->mFds.size();fi++)
+ for(size_t fi{0};fi < hData->mFds.size();++fi)
{
- for(ei = hData->mFds[fi].mEvStart;ei < hData->mFds[fi].mEvs.size();ei++)
+ for(size_t ei{hData->mFds[fi].mEvStart};ei < hData->mFds[fi].mEvs.size();++ei)
{
for(auto &azd : hData->mFds[fi].mEvs[ei].mAzs)
{
- for(ti = 0;ti < channels;ti++)
+ for(size_t ti{0};ti < channels;++ti)
{
- for(i = 0;i < m;i++)
+ for(size_t i{0};i < m;++i)
azd.mIrs[ti][i] /= dfa[(ti * m) + i];
}
}
@@ -624,7 +619,8 @@ static void DiffuseFieldEqualize(const uint channels, const uint m, const double
*/
static void CalcAzIndices(const HrirFdT &field, const uint ei, const double az, uint *a0, uint *a1, double *af)
{
- double f{(2.0*M_PI + az) * static_cast<double>(field.mEvs[ei].mAzs.size()) / (2.0*M_PI)};
+ double f{(2.0*al::numbers::pi + az) * static_cast<double>(field.mEvs[ei].mAzs.size()) /
+ (2.0*al::numbers::pi)};
const uint i{static_cast<uint>(f) % static_cast<uint>(field.mEvs[ei].mAzs.size())};
f -= std::floor(f);
@@ -674,7 +670,7 @@ static void SynthesizeOnsets(HrirDataT *hData)
* the mirrored elevation to find the indices for the polar
* opposite position (may need blending).
*/
- const double az{field.mEvs[ei].mAzs[ai].mAzimuth + M_PI};
+ const double az{field.mEvs[ei].mAzs[ai].mAzimuth + al::numbers::pi};
CalcAzIndices(field, topElev, az, &a0, &a1, &af);
/* Blend the delays, and again, swap the ears. */
@@ -706,8 +702,8 @@ static void SynthesizeOnsets(HrirDataT *hData)
* measurement).
*/
double az{field.mEvs[ei].mAzs[ai].mAzimuth};
- if(az <= M_PI) az = M_PI - az;
- else az = (M_PI*2.0)-az + M_PI;
+ if(az <= al::numbers::pi) az = al::numbers::pi - az;
+ else az = (al::numbers::pi*2.0)-az + al::numbers::pi;
CalcAzIndices(field, topElev, az, &a0, &a1, &af);
field.mEvs[ei].mAzs[ai].mDelays[0] = Lerp(
@@ -735,12 +731,12 @@ static void SynthesizeOnsets(HrirDataT *hData)
double az{field.mEvs[ei].mAzs[ai].mAzimuth};
CalcAzIndices(field, upperElevReal, az, &a0, &a1, &af0);
CalcAzIndices(field, lowerElevFake, az, &a2, &a3, &af1);
- double blend[4]{
+ std::array<double,4> blend{{
(1.0-ef) * (1.0-af0),
(1.0-ef) * ( af0),
( ef) * (1.0-af1),
( ef) * ( af1)
- };
+ }};
for(uint ti{0u};ti < channels;ti++)
{
@@ -785,7 +781,7 @@ static void SynthesizeHrirs(HrirDataT *hData)
* and vice-versa, this produces a decent phantom-center response
* underneath the head.
*/
- CalcAzIndices(field, oi, ((ti==0) ? -M_PI : M_PI) / 2.0, &a0, &a1, &af);
+ CalcAzIndices(field, oi, al::numbers::pi / ((ti==0) ? -2.0 : 2.0), &a0, &a1, &af);
for(uint i{0u};i < m;i++)
{
field.mEvs[0].mAzs[0].mIrs[ti][i] = Lerp(field.mEvs[oi].mAzs[a0].mIrs[ti][i],
@@ -797,7 +793,7 @@ static void SynthesizeHrirs(HrirDataT *hData)
{
const double of{static_cast<double>(ei) / field.mEvStart};
const double b{(1.0 - of) * beta};
- double lp[4]{};
+ std::array<double,4> lp{};
/* Calculate a low-pass filter to simulate body occlusion. */
lp[0] = Lerp(1.0, lp[0], b);
@@ -842,7 +838,7 @@ static void SynthesizeHrirs(HrirDataT *hData)
}
}
const double b{beta};
- double lp[4]{};
+ std::array<double,4> lp{};
lp[0] = Lerp(1.0, lp[0], b);
lp[1] = Lerp(lp[0], lp[1], b);
lp[2] = Lerp(lp[1], lp[2], b);
@@ -877,10 +873,10 @@ static void SynthesizeHrirs(HrirDataT *hData)
*/
struct HrirReconstructor {
std::vector<double*> mIrs;
- std::atomic<size_t> mCurrent;
- std::atomic<size_t> mDone;
- uint mFftSize;
- uint mIrPoints;
+ std::atomic<size_t> mCurrent{};
+ std::atomic<size_t> mDone{};
+ uint mFftSize{};
+ uint mIrPoints{};
void Worker()
{
@@ -888,7 +884,7 @@ struct HrirReconstructor {
auto mags = std::vector<double>(mFftSize);
size_t m{(mFftSize/2) + 1};
- while(1)
+ while(true)
{
/* Load the current index to process. */
size_t idx{mCurrent.load()};
@@ -907,7 +903,7 @@ struct HrirReconstructor {
* time-domain response.
*/
for(size_t i{0};i < m;++i)
- mags[i] = std::max(mIrs[idx][i], EPSILON);
+ mags[i] = std::max(mIrs[idx][i], Epsilon);
MinimumPhase(mFftSize, mags.data(), h.data());
FftInverse(mFftSize, h.data());
for(uint i{0u};i < mIrPoints;++i)
@@ -991,7 +987,7 @@ static void NormalizeHrirs(HrirDataT *hData)
return LevelPair{std::max(current.amp, levels.amp), std::max(current.rms, levels.rms)};
};
auto measure_azi = [channels,mesasure_channel](const LevelPair levels, const HrirAzT &azi)
- { return std::accumulate(azi.mIrs, azi.mIrs+channels, levels, mesasure_channel); };
+ { return std::accumulate(azi.mIrs.begin(), azi.mIrs.begin()+channels, levels, mesasure_channel); };
auto measure_elev = [measure_azi](const LevelPair levels, const HrirEvT &elev)
{ return std::accumulate(elev.mAzs.cbegin(), elev.mAzs.cend(), levels, measure_azi); };
auto measure_field = [measure_elev](const LevelPair levels, const HrirFdT &field)
@@ -1018,7 +1014,7 @@ static void NormalizeHrirs(HrirDataT *hData)
auto proc_channel = [irSize,factor](double *ir)
{ std::transform(ir, ir+irSize, ir, [factor](double s){ return s * factor; }); };
auto proc_azi = [channels,proc_channel](HrirAzT &azi)
- { std::for_each(azi.mIrs, azi.mIrs+channels, proc_channel); };
+ { std::for_each(azi.mIrs.begin(), azi.mIrs.begin()+channels, proc_channel); };
auto proc_elev = [proc_azi](HrirEvT &elev)
{ std::for_each(elev.mAzs.begin(), elev.mAzs.end(), proc_azi); };
auto proc1_field = [proc_elev](HrirFdT &field)
@@ -1035,7 +1031,7 @@ static double CalcLTD(const double ev, const double az, const double rad, const
azp = std::asin(std::cos(ev) * std::sin(az));
dlp = std::sqrt((dist*dist) + (rad*rad) + (2.0*dist*rad*sin(azp)));
l = std::sqrt((dist*dist) - (rad*rad));
- al = (0.5 * M_PI) + azp;
+ al = (0.5 * al::numbers::pi) + azp;
if(dlp > l)
dlp = l + (rad * (al - std::acos(rad / dist)));
return dlp / 343.3;
@@ -1103,10 +1099,10 @@ static void CalculateHrtds(const HeadModelT model, const double radius, HrirData
}
}
}
- if(maxHrtd > MAX_HRTD)
+ if(maxHrtd > MaxHrtd)
{
- fprintf(stdout, " Scaling for max delay of %f samples to %f\n...\n", maxHrtd, MAX_HRTD);
- const double scale{MAX_HRTD / maxHrtd};
+ fprintf(stdout, " Scaling for max delay of %f samples to %f\n...\n", maxHrtd, MaxHrtd);
+ const double scale{MaxHrtd / maxHrtd};
for(auto &field : hData->mFds)
{
for(auto &elev : field.mEvs)
@@ -1153,11 +1149,12 @@ bool PrepareHrirData(const al::span<const double> distances,
{
uint azCount = azCounts[fi][ei];
- hData->mFds[fi].mEvs[ei].mElevation = -M_PI / 2.0 + M_PI * ei / (evCounts[fi] - 1);
+ hData->mFds[fi].mEvs[ei].mElevation = -al::numbers::pi / 2.0 + al::numbers::pi * ei /
+ (evCounts[fi] - 1);
hData->mFds[fi].mEvs[ei].mAzs = {&hData->mAzsBase[azTotal], azCount};
for(uint ai{0};ai < azCount;ai++)
{
- hData->mFds[fi].mEvs[ei].mAzs[ai].mAzimuth = 2.0 * M_PI * ai / azCount;
+ hData->mFds[fi].mEvs[ei].mAzs[ai].mAzimuth = 2.0 * al::numbers::pi * ai / azCount;
hData->mFds[fi].mEvs[ei].mAzs[ai].mIndex = azTotal + ai;
hData->mFds[fi].mEvs[ei].mAzs[ai].mDelays[0] = 0.0;
hData->mFds[fi].mEvs[ei].mAzs[ai].mDelays[1] = 0.0;
@@ -1199,10 +1196,10 @@ static int ProcessDefinition(const char *inName, const uint outRate, const Chann
return 0;
}
- char startbytes[4]{};
- input->read(startbytes, sizeof(startbytes));
+ std::array<char,4> startbytes{};
+ input->read(startbytes.data(), startbytes.size());
std::streamsize startbytecount{input->gcount()};
- if(startbytecount != sizeof(startbytes) || !input->good())
+ if(startbytecount != startbytes.size() || !input->good())
{
fprintf(stderr, "Error: Could not read input file '%s'\n", inName);
return 0;
@@ -1219,7 +1216,8 @@ static int ProcessDefinition(const char *inName, const uint outRate, const Chann
else
{
fprintf(stdout, "Reading HRIR definition from %s...\n", inName);
- if(!LoadDefInput(*input, startbytes, startbytecount, inName, fftSize, truncSize, outRate, chanMode, &hData))
+ if(!LoadDefInput(*input, startbytes.data(), startbytecount, inName, fftSize, truncSize,
+ outRate, chanMode, &hData))
return 0;
}
}
@@ -1228,7 +1226,7 @@ static int ProcessDefinition(const char *inName, const uint outRate, const Chann
{
uint c{(hData.mChannelType == CT_STEREO) ? 2u : 1u};
uint m{hData.mFftSize/2u + 1u};
- auto dfa = std::vector<double>(c * m);
+ auto dfa = std::vector<double>(size_t{c} * m);
if(hData.mFds.size() > 1)
{
@@ -1264,7 +1262,7 @@ static int ProcessDefinition(const char *inName, const uint outRate, const Chann
fprintf(stdout, "Normalizing final HRIRs...\n");
NormalizeHrirs(&hData);
fprintf(stdout, "Calculating impulse delays...\n");
- CalculateHrtds(model, (radius > DEFAULT_CUSTOM_RADIUS) ? radius : hData.mRadius, &hData);
+ CalculateHrtds(model, (radius > DefaultCustomRadius) ? radius : hData.mRadius, &hData);
const auto rateStr = std::to_string(hData.mIrRate);
const auto expName = StrSubst({outName, strlen(outName)}, {"%r", 2},
@@ -1283,13 +1281,13 @@ static void PrintHelp(const char *argv0, FILE *ofile)
fprintf(ofile, " right ear.\n");
fprintf(ofile, " -a Change the data set to single field, using the farthest field.\n");
fprintf(ofile, " -j <threads> Number of threads used to process HRIRs (default: 2).\n");
- fprintf(ofile, " -f <points> Override the FFT window size (default: %u).\n", DEFAULT_FFTSIZE);
- fprintf(ofile, " -e {on|off} Toggle diffuse-field equalization (default: %s).\n", (DEFAULT_EQUALIZE ? "on" : "off"));
- fprintf(ofile, " -s {on|off} Toggle surface-weighted diffuse-field average (default: %s).\n", (DEFAULT_SURFACE ? "on" : "off"));
+ fprintf(ofile, " -f <points> Override the FFT window size (default: %u).\n", DefaultFftSize);
+ fprintf(ofile, " -e {on|off} Toggle diffuse-field equalization (default: %s).\n", (DefaultEqualize ? "on" : "off"));
+ fprintf(ofile, " -s {on|off} Toggle surface-weighted diffuse-field average (default: %s).\n", (DefaultSurface ? "on" : "off"));
fprintf(ofile, " -l {<dB>|none} Specify a limit to the magnitude range of the diffuse-field\n");
- fprintf(ofile, " average (default: %.2f).\n", DEFAULT_LIMIT);
+ fprintf(ofile, " average (default: %.2f).\n", DefaultLimit);
fprintf(ofile, " -w <points> Specify the size of the truncation window that's applied\n");
- fprintf(ofile, " after minimum-phase reconstruction (default: %u).\n", DEFAULT_TRUNCSIZE);
+ fprintf(ofile, " after minimum-phase reconstruction (default: %u).\n", DefaultTruncSize);
fprintf(ofile, " -d {dataset| Specify the model used for calculating the head-delay timing\n");
fprintf(ofile, " sphere} values (default: %s).\n", ((DEFAULT_HEAD_MODEL == HM_DATASET) ? "dataset" : "sphere"));
fprintf(ofile, " -c <radius> Use a customized head radius measured to-ear in meters.\n");
@@ -1324,14 +1322,14 @@ int main(int argc, char *argv[])
outName = "./oalsoft_hrtf_%r.mhr";
outRate = 0;
chanMode = CM_AllowStereo;
- fftSize = DEFAULT_FFTSIZE;
- equalize = DEFAULT_EQUALIZE;
- surface = DEFAULT_SURFACE;
- limit = DEFAULT_LIMIT;
+ fftSize = DefaultFftSize;
+ equalize = DefaultEqualize;
+ surface = DefaultSurface;
+ limit = DefaultLimit;
numThreads = 2;
- truncSize = DEFAULT_TRUNCSIZE;
+ truncSize = DefaultTruncSize;
model = DEFAULT_HEAD_MODEL;
- radius = DEFAULT_CUSTOM_RADIUS;
+ radius = DefaultCustomRadius;
farfield = false;
while((opt=getopt(argc, argv, "r:maj:f:e:s:l:w:d:c:e:i:o:h")) != -1)
@@ -1368,9 +1366,9 @@ int main(int argc, char *argv[])
case 'f':
fftSize = static_cast<uint>(strtoul(optarg, &end, 10));
- if(end[0] != '\0' || (fftSize&(fftSize-1)) || fftSize < MIN_FFTSIZE || fftSize > MAX_FFTSIZE)
+ if(end[0] != '\0' || (fftSize&(fftSize-1)) || fftSize < MinFftSize || fftSize > MaxFftSize)
{
- fprintf(stderr, "\nError: Got unexpected value \"%s\" for option -%c, expected a power-of-two between %u to %u.\n", optarg, opt, MIN_FFTSIZE, MAX_FFTSIZE);
+ fprintf(stderr, "\nError: Got unexpected value \"%s\" for option -%c, expected a power-of-two between %u to %u.\n", optarg, opt, MinFftSize, MaxFftSize);
exit(EXIT_FAILURE);
}
break;
@@ -1405,9 +1403,9 @@ int main(int argc, char *argv[])
else
{
limit = strtod(optarg, &end);
- if(end[0] != '\0' || limit < MIN_LIMIT || limit > MAX_LIMIT)
+ if(end[0] != '\0' || limit < MinLimit || limit > MaxLimit)
{
- fprintf(stderr, "\nError: Got unexpected value \"%s\" for option -%c, expected between %.0f to %.0f.\n", optarg, opt, MIN_LIMIT, MAX_LIMIT);
+ fprintf(stderr, "\nError: Got unexpected value \"%s\" for option -%c, expected between %.0f to %.0f.\n", optarg, opt, MinLimit, MaxLimit);
exit(EXIT_FAILURE);
}
}
@@ -1415,9 +1413,9 @@ int main(int argc, char *argv[])
case 'w':
truncSize = static_cast<uint>(strtoul(optarg, &end, 10));
- if(end[0] != '\0' || truncSize < MIN_TRUNCSIZE || truncSize > MAX_TRUNCSIZE)
+ if(end[0] != '\0' || truncSize < MinTruncSize || truncSize > MaxTruncSize)
{
- fprintf(stderr, "\nError: Got unexpected value \"%s\" for option -%c, expected between %u to %u.\n", optarg, opt, MIN_TRUNCSIZE, MAX_TRUNCSIZE);
+ fprintf(stderr, "\nError: Got unexpected value \"%s\" for option -%c, expected between %u to %u.\n", optarg, opt, MinTruncSize, MaxTruncSize);
exit(EXIT_FAILURE);
}
break;
@@ -1436,9 +1434,9 @@ int main(int argc, char *argv[])
case 'c':
radius = strtod(optarg, &end);
- if(end[0] != '\0' || radius < MIN_CUSTOM_RADIUS || radius > MAX_CUSTOM_RADIUS)
+ if(end[0] != '\0' || radius < MinCustomRadius || radius > MaxCustomRadius)
{
- fprintf(stderr, "\nError: Got unexpected value \"%s\" for option -%c, expected between %.2f to %.2f.\n", optarg, opt, MIN_CUSTOM_RADIUS, MAX_CUSTOM_RADIUS);
+ fprintf(stderr, "\nError: Got unexpected value \"%s\" for option -%c, expected between %.2f to %.2f.\n", optarg, opt, MinCustomRadius, MaxCustomRadius);
exit(EXIT_FAILURE);
}
break;
diff --git a/utils/makemhr/makemhr.h b/utils/makemhr/makemhr.h
index aa18134d..71c2e55b 100644
--- a/utils/makemhr/makemhr.h
+++ b/utils/makemhr/makemhr.h
@@ -9,35 +9,43 @@
// The maximum path length used when processing filenames.
-#define MAX_PATH_LEN (256)
+enum { MAX_PATH_LEN = 256u };
// The limit to the number of 'distances' listed in the data set definition.
// Must be less than 256
-#define MAX_FD_COUNT (16)
+enum { MAX_FD_COUNT = 16u };
// The limits to the number of 'elevations' listed in the data set definition.
// Must be less than 256.
-#define MIN_EV_COUNT (5)
-#define MAX_EV_COUNT (181)
+enum {
+ MIN_EV_COUNT = 5u,
+ MAX_EV_COUNT = 181u
+};
// The limits for each of the 'azimuths' listed in the data set definition.
// Must be less than 256.
-#define MIN_AZ_COUNT (1)
-#define MAX_AZ_COUNT (255)
+enum {
+ MIN_AZ_COUNT = 1u,
+ MAX_AZ_COUNT = 255u
+};
// The limits for the 'distance' from source to listener for each field in
// the definition file.
-#define MIN_DISTANCE (0.05)
-#define MAX_DISTANCE (2.50)
+inline constexpr double MIN_DISTANCE{0.05};
+inline constexpr double MAX_DISTANCE{2.50};
// The limits for the sample 'rate' metric in the data set definition and for
// resampling.
-#define MIN_RATE (32000)
-#define MAX_RATE (96000)
+enum {
+ MIN_RATE = 32000u,
+ MAX_RATE = 96000u
+};
// The limits for the HRIR 'points' metric in the data set definition.
-#define MIN_POINTS (16)
-#define MAX_POINTS (8192)
+enum {
+ MIN_POINTS = 16u,
+ MAX_POINTS = 8192u
+};
using uint = unsigned int;
@@ -68,8 +76,8 @@ enum ChannelTypeT {
struct HrirAzT {
double mAzimuth{0.0};
uint mIndex{0u};
- double mDelays[2]{0.0, 0.0};
- double *mIrs[2]{nullptr, nullptr};
+ std::array<double,2> mDelays{};
+ std::array<double*,2> mIrs{};
};
struct HrirEvT {
diff --git a/utils/openal-info.c b/utils/openal-info.c
index 8ef6ebde..669727a6 100644
--- a/utils/openal-info.c
+++ b/utils/openal-info.c
@@ -45,11 +45,11 @@
#define FUNCTION_CAST(T, ptr) (T)(ptr)
#endif
-#define MAX_WIDTH 80
+enum { MaxWidth = 80 };
static void printList(const char *list, char separator)
{
- size_t col = MAX_WIDTH, len;
+ size_t col = MaxWidth, len;
const char *indent = " ";
const char *next;
@@ -71,7 +71,7 @@ static void printList(const char *list, char separator)
else
len = strlen(list);
- if(len + col + 2 >= MAX_WIDTH)
+ if(len + col + 2 >= MaxWidth)
{
fprintf(stdout, "\n%s", indent);
col = strlen(indent);
@@ -181,6 +181,14 @@ static void printHRTFInfo(ALCdevice *device)
checkALCErrors(device);
}
+static void printALCIntegerValue(ALCdevice *device, ALCenum enumValue, char* enumName)
+{
+ ALCint value;
+ alcGetIntegerv(device, enumValue, 1, &value);
+ if (checkALCErrors(device) == ALC_NO_ERROR)
+ printf("%s: %d\n", enumName, value);
+}
+
static void printModeInfo(ALCdevice *device)
{
ALCint srate = 0;
@@ -228,6 +236,9 @@ static void printModeInfo(ALCdevice *device)
}
printf("Device HRTF profile: %s\n", hrtfname ? hrtfname : "<null>");
}
+
+ printALCIntegerValue(device, ALC_MONO_SOURCES, "Device number of mono sources");
+ printALCIntegerValue(device, ALC_STEREO_SOURCES, "Device number of stereo sources");
}
static void printALCSOFTSystemEventIsSupportedResult(LPALCEVENTISSUPPORTEDSOFT alcEventIsSupportedSOFT, ALCenum eventType, ALCenum deviceType)
@@ -382,7 +393,7 @@ static void printEFXInfo(ALCdevice *device)
palFilteri(object, AL_FILTER_TYPE, filters[i]);
if(alGetError() != AL_NO_ERROR)
- memmove(current, next+1, strlen(next));
+ memmove(current, next+1, strlen(next)); /* NOLINT(clang-analyzer-security.insecureAPI.*) */
else
current = next+1;
}
@@ -401,7 +412,7 @@ static void printEFXInfo(ALCdevice *device)
palEffecti(object, AL_EFFECT_TYPE, effects[i]);
if(alGetError() != AL_NO_ERROR)
- memmove(current, next+1, strlen(next));
+ memmove(current, next+1, strlen(next)); /* NOLINT(clang-analyzer-security.insecureAPI.*) */
else
current = next+1;
}
@@ -414,7 +425,7 @@ static void printEFXInfo(ALCdevice *device)
palEffecti(object, AL_EFFECT_TYPE, dedeffects[i]);
if(alGetError() != AL_NO_ERROR)
- memmove(current, next+1, strlen(next));
+ memmove(current, next+1, strlen(next)); /* NOLINT(clang-analyzer-security.insecureAPI.*) */
else
current = next+1;
}
@@ -425,7 +436,7 @@ static void printEFXInfo(ALCdevice *device)
{
char *next = strchr(current, ',');
assert(next != NULL);
- memmove(current, next+1, strlen(next));
+ memmove(current, next+1, strlen(next)); /* NOLINT(clang-analyzer-security.insecureAPI.*) */
}
}
printf("Supported effects:");
diff --git a/utils/sofa-info.cpp b/utils/sofa-info.cpp
index 6dffef44..7775b8e3 100644
--- a/utils/sofa-info.cpp
+++ b/utils/sofa-info.cpp
@@ -21,8 +21,7 @@
* Or visit: http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*/
-#include <stdio.h>
-
+#include <cstdio>
#include <memory>
#include <vector>
diff --git a/utils/sofa-support.cpp b/utils/sofa-support.cpp
index e37789d5..ceb3067a 100644
--- a/utils/sofa-support.cpp
+++ b/utils/sofa-support.cpp
@@ -24,11 +24,11 @@
#include "sofa-support.h"
-#include <stdio.h>
#include <algorithm>
#include <array>
#include <cmath>
+#include <cstdio>
#include <utility>
#include <vector>
@@ -47,7 +47,7 @@ using double3 = std::array<double,3>;
* equality of unique elements.
*/
std::vector<double> GetUniquelySortedElems(const std::vector<double3> &aers, const uint axis,
- const double *const (&filters)[3], const double (&epsilons)[3])
+ const std::array<const double*,3> filters, const std::array<double,3> epsilons)
{
std::vector<double> elems;
for(const double3 &aer : aers)
@@ -183,8 +183,8 @@ std::vector<SofaField> GetCompatibleLayout(const size_t m, const float *xyzs)
auto aers = std::vector<double3>(m, double3{});
for(size_t i{0u};i < m;++i)
{
- float vals[3]{xyzs[i*3], xyzs[i*3 + 1], xyzs[i*3 + 2]};
- mysofa_c2s(&vals[0]);
+ std::array vals{xyzs[i*3], xyzs[i*3 + 1], xyzs[i*3 + 2]};
+ mysofa_c2s(vals.data());
aers[i] = {vals[0], vals[1], vals[2]};
}
diff --git a/utils/uhjdecoder.cpp b/utils/uhjdecoder.cpp
index c7efa376..970d9f82 100644
--- a/utils/uhjdecoder.cpp
+++ b/utils/uhjdecoder.cpp
@@ -48,7 +48,7 @@
struct FileDeleter {
- void operator()(FILE *file) { fclose(file); }
+ void operator()(gsl::owner<FILE*> file) { fclose(file); }
};
using FilePtr = std::unique_ptr<FILE,FileDeleter>;
@@ -66,22 +66,22 @@ using complex_d = std::complex<double>;
using byte4 = std::array<std::byte,4>;
-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);
}
template<al::endian = al::endian::native>
@@ -129,8 +129,6 @@ struct UhjDecoder {
const al::span<FloatBufferLine> OutSamples, const std::size_t SamplesToDo);
void decode2(const float *RESTRICT InSamples, const al::span<FloatBufferLine> OutSamples,
const std::size_t SamplesToDo);
-
- DEF_NEWDEL(UhjDecoder)
};
const PhaseShifterT<UhjDecoder::sFilterDelay*2> PShift{};
@@ -389,7 +387,7 @@ int main(int argc, char **argv)
fprintf(stderr, "Failed to open %s\n", argv[fidx]);
continue;
}
- if(sf_command(infile.get(), SFC_WAVEX_GET_AMBISONIC, NULL, 0) == SF_AMBISONIC_B_FORMAT)
+ if(sf_command(infile.get(), SFC_WAVEX_GET_AMBISONIC, nullptr, 0) == SF_AMBISONIC_B_FORMAT)
{
fprintf(stderr, "%s is already B-Format\n", argv[fidx]);
continue;
@@ -438,7 +436,7 @@ int main(int argc, char **argv)
// 32-bit val, frequency
fwrite32le(static_cast<uint>(ininfo.samplerate), outfile.get());
// 32-bit val, bytes per second
- fwrite32le(static_cast<uint>(ininfo.samplerate)*sizeof(float)*outchans, outfile.get());
+ fwrite32le(static_cast<uint>(ininfo.samplerate)*outchans*uint{sizeof(float)}, outfile.get());
// 16-bit val, frame size
fwrite16le(static_cast<ushort>(sizeof(float)*outchans), outfile.get());
// 16-bit val, bits per sample
@@ -450,7 +448,7 @@ int main(int argc, char **argv)
// 32-bit val, channel mask
fwrite32le(0, outfile.get());
// 16 byte GUID, sub-type format
- fwrite(SUBTYPE_BFORMAT_FLOAT, 1, 16, outfile.get());
+ fwrite(SUBTYPE_BFORMAT_FLOAT.data(), 1, SUBTYPE_BFORMAT_FLOAT.size(), outfile.get());
fputs("data", outfile.get());
fwrite32le(0xFFFFFFFF, outfile.get()); // 'data' header len; filled in at close
@@ -463,9 +461,9 @@ int main(int argc, char **argv)
auto DataStart = ftell(outfile.get());
auto decoder = std::make_unique<UhjDecoder>();
- auto inmem = std::make_unique<float[]>(BufferLineSize*static_cast<uint>(ininfo.channels));
+ auto inmem = std::vector<float>(size_t{BufferLineSize}*static_cast<uint>(ininfo.channels));
auto decmem = al::vector<std::array<float,BufferLineSize>, 16>(outchans);
- auto outmem = std::make_unique<byte4[]>(BufferLineSize*outchans);
+ auto outmem = std::vector<byte4>(size_t{BufferLineSize}*outchans);
/* A number of initial samples need to be skipped to cut the lead-in
* from the all-pass filter delay. The same number of samples need to
@@ -476,21 +474,21 @@ int main(int argc, char **argv)
sf_count_t LeadOut{UhjDecoder::sFilterDelay};
while(LeadOut > 0)
{
- sf_count_t sgot{sf_readf_float(infile.get(), inmem.get(), BufferLineSize)};
+ sf_count_t sgot{sf_readf_float(infile.get(), inmem.data(), BufferLineSize)};
sgot = std::max<sf_count_t>(sgot, 0);
if(sgot < BufferLineSize)
{
const sf_count_t remaining{std::min(BufferLineSize - sgot, LeadOut)};
- std::fill_n(inmem.get() + sgot*ininfo.channels, remaining*ininfo.channels, 0.0f);
+ std::fill_n(inmem.data() + sgot*ininfo.channels, remaining*ininfo.channels, 0.0f);
sgot += remaining;
LeadOut -= remaining;
}
auto got = static_cast<std::size_t>(sgot);
if(ininfo.channels > 2 || use_general)
- decoder->decode(inmem.get(), static_cast<uint>(ininfo.channels), decmem, got);
+ decoder->decode(inmem.data(), static_cast<uint>(ininfo.channels), decmem, got);
else
- decoder->decode2(inmem.get(), decmem, got);
+ decoder->decode2(inmem.data(), decmem, got);
if(LeadIn >= got)
{
LeadIn -= got;
@@ -507,7 +505,7 @@ int main(int argc, char **argv)
}
LeadIn = 0;
- std::size_t wrote{fwrite(outmem.get(), sizeof(byte4)*outchans, got, outfile.get())};
+ std::size_t wrote{fwrite(outmem.data(), sizeof(byte4)*outchans, got, outfile.get())};
if(wrote < got)
{
fprintf(stderr, "Error writing wave data: %s (%d)\n", strerror(errno), errno);
diff --git a/utils/uhjencoder.cpp b/utils/uhjencoder.cpp
index 154a1155..02836181 100644
--- a/utils/uhjencoder.cpp
+++ b/utils/uhjencoder.cpp
@@ -26,14 +26,13 @@
#include <array>
#include <cinttypes>
+#include <cstddef>
#include <cstring>
#include <memory>
-#include <stddef.h>
#include <string>
#include <utility>
#include <vector>
-#include "almalloc.h"
#include "alnumbers.h"
#include "alspan.h"
#include "opthelpers.h"
@@ -82,8 +81,6 @@ struct UhjEncoder {
void encode(const al::span<FloatBufferLine> OutSamples,
const al::span<FloatBufferLine,4> InSamples, const size_t SamplesToDo);
-
- DEF_NEWDEL(UhjEncoder)
};
const PhaseShifterT<UhjEncoder::sFilterDelay*2> PShift{};
@@ -179,50 +176,55 @@ struct SpeakerPos {
};
/* Azimuth is counter-clockwise. */
-constexpr SpeakerPos StereoMap[2]{
- { SF_CHANNEL_MAP_LEFT, 30.0f, 0.0f },
- { SF_CHANNEL_MAP_RIGHT, -30.0f, 0.0f },
-}, QuadMap[4]{
- { SF_CHANNEL_MAP_LEFT, 45.0f, 0.0f },
- { SF_CHANNEL_MAP_RIGHT, -45.0f, 0.0f },
- { SF_CHANNEL_MAP_REAR_LEFT, 135.0f, 0.0f },
- { SF_CHANNEL_MAP_REAR_RIGHT, -135.0f, 0.0f },
-}, X51Map[6]{
- { SF_CHANNEL_MAP_LEFT, 30.0f, 0.0f },
- { SF_CHANNEL_MAP_RIGHT, -30.0f, 0.0f },
- { SF_CHANNEL_MAP_CENTER, 0.0f, 0.0f },
- { SF_CHANNEL_MAP_LFE, 0.0f, 0.0f },
- { SF_CHANNEL_MAP_SIDE_LEFT, 110.0f, 0.0f },
- { SF_CHANNEL_MAP_SIDE_RIGHT, -110.0f, 0.0f },
-}, X51RearMap[6]{
- { SF_CHANNEL_MAP_LEFT, 30.0f, 0.0f },
- { SF_CHANNEL_MAP_RIGHT, -30.0f, 0.0f },
- { SF_CHANNEL_MAP_CENTER, 0.0f, 0.0f },
- { SF_CHANNEL_MAP_LFE, 0.0f, 0.0f },
- { SF_CHANNEL_MAP_REAR_LEFT, 110.0f, 0.0f },
- { SF_CHANNEL_MAP_REAR_RIGHT, -110.0f, 0.0f },
-}, X71Map[8]{
- { SF_CHANNEL_MAP_LEFT, 30.0f, 0.0f },
- { SF_CHANNEL_MAP_RIGHT, -30.0f, 0.0f },
- { SF_CHANNEL_MAP_CENTER, 0.0f, 0.0f },
- { SF_CHANNEL_MAP_LFE, 0.0f, 0.0f },
- { SF_CHANNEL_MAP_REAR_LEFT, 150.0f, 0.0f },
- { SF_CHANNEL_MAP_REAR_RIGHT, -150.0f, 0.0f },
- { SF_CHANNEL_MAP_SIDE_LEFT, 90.0f, 0.0f },
- { SF_CHANNEL_MAP_SIDE_RIGHT, -90.0f, 0.0f },
-}, X714Map[12]{
- { SF_CHANNEL_MAP_LEFT, 30.0f, 0.0f },
- { SF_CHANNEL_MAP_RIGHT, -30.0f, 0.0f },
- { SF_CHANNEL_MAP_CENTER, 0.0f, 0.0f },
- { SF_CHANNEL_MAP_LFE, 0.0f, 0.0f },
- { SF_CHANNEL_MAP_REAR_LEFT, 150.0f, 0.0f },
- { SF_CHANNEL_MAP_REAR_RIGHT, -150.0f, 0.0f },
- { SF_CHANNEL_MAP_SIDE_LEFT, 90.0f, 0.0f },
- { SF_CHANNEL_MAP_SIDE_RIGHT, -90.0f, 0.0f },
- { SF_CHANNEL_MAP_TOP_FRONT_LEFT, 45.0f, 35.0f },
- { SF_CHANNEL_MAP_TOP_FRONT_RIGHT, -45.0f, 35.0f },
- { SF_CHANNEL_MAP_TOP_REAR_LEFT, 135.0f, 35.0f },
- { SF_CHANNEL_MAP_TOP_REAR_RIGHT, -135.0f, 35.0f },
+constexpr std::array StereoMap{
+ SpeakerPos{SF_CHANNEL_MAP_LEFT, 30.0f, 0.0f},
+ SpeakerPos{SF_CHANNEL_MAP_RIGHT, -30.0f, 0.0f},
+};
+constexpr std::array QuadMap{
+ SpeakerPos{SF_CHANNEL_MAP_LEFT, 45.0f, 0.0f},
+ SpeakerPos{SF_CHANNEL_MAP_RIGHT, -45.0f, 0.0f},
+ SpeakerPos{SF_CHANNEL_MAP_REAR_LEFT, 135.0f, 0.0f},
+ SpeakerPos{SF_CHANNEL_MAP_REAR_RIGHT, -135.0f, 0.0f},
+};
+constexpr std::array X51Map{
+ SpeakerPos{SF_CHANNEL_MAP_LEFT, 30.0f, 0.0f},
+ SpeakerPos{SF_CHANNEL_MAP_RIGHT, -30.0f, 0.0f},
+ SpeakerPos{SF_CHANNEL_MAP_CENTER, 0.0f, 0.0f},
+ SpeakerPos{SF_CHANNEL_MAP_LFE, 0.0f, 0.0f},
+ SpeakerPos{SF_CHANNEL_MAP_SIDE_LEFT, 110.0f, 0.0f},
+ SpeakerPos{SF_CHANNEL_MAP_SIDE_RIGHT, -110.0f, 0.0f},
+};
+constexpr std::array X51RearMap{
+ SpeakerPos{SF_CHANNEL_MAP_LEFT, 30.0f, 0.0f},
+ SpeakerPos{SF_CHANNEL_MAP_RIGHT, -30.0f, 0.0f},
+ SpeakerPos{SF_CHANNEL_MAP_CENTER, 0.0f, 0.0f},
+ SpeakerPos{SF_CHANNEL_MAP_LFE, 0.0f, 0.0f},
+ SpeakerPos{SF_CHANNEL_MAP_REAR_LEFT, 110.0f, 0.0f},
+ SpeakerPos{SF_CHANNEL_MAP_REAR_RIGHT, -110.0f, 0.0f},
+};
+constexpr std::array X71Map{
+ SpeakerPos{SF_CHANNEL_MAP_LEFT, 30.0f, 0.0f},
+ SpeakerPos{SF_CHANNEL_MAP_RIGHT, -30.0f, 0.0f},
+ SpeakerPos{SF_CHANNEL_MAP_CENTER, 0.0f, 0.0f},
+ SpeakerPos{SF_CHANNEL_MAP_LFE, 0.0f, 0.0f},
+ SpeakerPos{SF_CHANNEL_MAP_REAR_LEFT, 150.0f, 0.0f},
+ SpeakerPos{SF_CHANNEL_MAP_REAR_RIGHT, -150.0f, 0.0f},
+ SpeakerPos{SF_CHANNEL_MAP_SIDE_LEFT, 90.0f, 0.0f},
+ SpeakerPos{SF_CHANNEL_MAP_SIDE_RIGHT, -90.0f, 0.0f},
+};
+constexpr std::array X714Map{
+ SpeakerPos{SF_CHANNEL_MAP_LEFT, 30.0f, 0.0f},
+ SpeakerPos{SF_CHANNEL_MAP_RIGHT, -30.0f, 0.0f},
+ SpeakerPos{SF_CHANNEL_MAP_CENTER, 0.0f, 0.0f},
+ SpeakerPos{SF_CHANNEL_MAP_LFE, 0.0f, 0.0f},
+ SpeakerPos{SF_CHANNEL_MAP_REAR_LEFT, 150.0f, 0.0f},
+ SpeakerPos{SF_CHANNEL_MAP_REAR_RIGHT, -150.0f, 0.0f},
+ SpeakerPos{SF_CHANNEL_MAP_SIDE_LEFT, 90.0f, 0.0f},
+ SpeakerPos{SF_CHANNEL_MAP_SIDE_RIGHT, -90.0f, 0.0f},
+ SpeakerPos{SF_CHANNEL_MAP_TOP_FRONT_LEFT, 45.0f, 35.0f},
+ SpeakerPos{SF_CHANNEL_MAP_TOP_FRONT_RIGHT, -45.0f, 35.0f},
+ SpeakerPos{SF_CHANNEL_MAP_TOP_REAR_LEFT, 135.0f, 35.0f},
+ SpeakerPos{SF_CHANNEL_MAP_TOP_REAR_RIGHT, -135.0f, 35.0f},
};
constexpr auto GenCoeffs(double x /*+front*/, double y /*+left*/, double z /*+up*/) noexcept
@@ -413,11 +415,11 @@ int main(int argc, char **argv)
}
auto encoder = std::make_unique<UhjEncoder>();
- auto splbuf = al::vector<FloatBufferLine, 16>(static_cast<uint>(9+ininfo.channels)+uhjchans);
- auto ambmem = al::span<FloatBufferLine,4>{splbuf.data(), 4};
- auto encmem = al::span<FloatBufferLine,4>{&splbuf[4], 4};
- auto srcmem = al::span<float,BufferLineSize>{splbuf[8].data(), BufferLineSize};
- auto outmem = al::span<float>{splbuf[9].data(), BufferLineSize*uhjchans};
+ auto splbuf = al::vector<FloatBufferLine, 16>(static_cast<uint>(ininfo.channels)+9+size_t{uhjchans});
+ auto ambmem = al::span{splbuf}.subspan<0,4>();
+ auto encmem = al::span{splbuf}.subspan<4,4>();
+ auto srcmem = al::span{splbuf[8]};
+ auto outmem = al::span<float>{splbuf[9].data(), size_t{BufferLineSize}*uhjchans};
/* A number of initial samples need to be skipped to cut the lead-in
* from the all-pass filter delay. The same number of samples need to