From 7e5dd4196846f61307e156d55ae0fc12fbd29512 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 8 Aug 2022 03:44:25 -0700 Subject: [PATCH] Add an option for higher quality UHJ filters --- alc/alc.cpp | 40 ++++++++++++++++++++++++++-------------- alc/panning.cpp | 5 ++++- alsoftrc.sample | 12 ++++++++++++ core/uhjfilter.cpp | 3 +++ core/uhjfilter.h | 2 ++ core/voice.cpp | 24 ++++++++++++++++++++---- 6 files changed, 67 insertions(+), 19 deletions(-) diff --git a/alc/alc.cpp b/alc/alc.cpp index d17969f4..571088c9 100644 --- a/alc/alc.cpp +++ b/alc/alc.cpp @@ -1124,25 +1124,37 @@ void alc_initconfig(void) if(auto limopt = ConfigValueBool(nullptr, nullptr, "rt-time-limit")) AllowRTTimeLimit = *limopt; - CompatFlagBitset compatflags{}; - auto checkflag = [](const char *envname, const char *optname) -> bool { - if(auto optval = al::getenv(envname)) + CompatFlagBitset compatflags{}; + auto checkflag = [](const char *envname, const char *optname) -> bool { - if(al::strcasecmp(optval->c_str(), "true") == 0 - || strtol(optval->c_str(), nullptr, 0) == 1) - return true; - return false; - } - return GetConfigValueBool(nullptr, "game_compat", optname, false); - }; - 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")); + if(auto optval = al::getenv(envname)) + { + if(al::strcasecmp(optval->c_str(), "true") == 0 + || strtol(optval->c_str(), nullptr, 0) == 1) + return true; + return false; + } + return GetConfigValueBool(nullptr, "game_compat", optname, false); + }; + 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(nullptr, "game_compat", "nfc-scale").value_or(1.0f)); + } Voice::InitMixer(ConfigValueStr(nullptr, nullptr, "resampler")); + if(auto uhjfiltopt = ConfigValueStr(nullptr, "uhj", "filter-type")) + { + if(al::strcasecmp(uhjfiltopt->c_str(), "fir256") == 0) + UhjQuality = UhjLengthLq; + else if(al::strcasecmp(uhjfiltopt->c_str(), "fir512") == 0) + UhjQuality = UhjLengthHq; + else + WARN("Unsupported uhj/filter-type: %s\n", uhjfiltopt->c_str()); + } + auto traperr = al::getenv("ALSOFT_TRAP_ERROR"); if(traperr && (al::strcasecmp(traperr->c_str(), "true") == 0 || std::strtol(traperr->c_str(), nullptr, 0) == 1)) diff --git a/alc/panning.cpp b/alc/panning.cpp index 22688bc9..ea716e4d 100644 --- a/alc/panning.cpp +++ b/alc/panning.cpp @@ -1093,7 +1093,10 @@ void aluInitRenderer(ALCdevice *device, int hrtf_id, al::optionalmUhjEncoder = std::make_unique>(); + if(UhjQuality >= UhjLengthHq) + device->mUhjEncoder = std::make_unique>(); + else + device->mUhjEncoder = std::make_unique>(); TRACE("UHJ enabled\n"); InitUhjPanning(device); device->PostProcess = &ALCdevice::ProcessUhj; diff --git a/alsoftrc.sample b/alsoftrc.sample index f804029f..9097ae1d 100644 --- a/alsoftrc.sample +++ b/alsoftrc.sample @@ -348,6 +348,18 @@ # docs/3D7.1.txt for information about 3D7.1. #surround3d71 = +## +## UHJ stuff +## +[uhj] + +## filter-type: (global) +# Specifies the all-pass filter type for UHJ encoding, decoding, and Super +# Stereo processing. The default is 'fir256', which utilizes a 256-point FIR +# filter. 'fir512' is a 512-point FIR filter, providing higher quality at the +# cost of higher CPU use. +#filter-type = fir256 + ## ## Reverb effect stuff (includes EAX reverb) ## diff --git a/core/uhjfilter.cpp b/core/uhjfilter.cpp index b327a627..4917ffa8 100644 --- a/core/uhjfilter.cpp +++ b/core/uhjfilter.cpp @@ -12,6 +12,9 @@ #include "phase_shifter.h" +size_t UhjQuality{UhjLengthStd}; + + namespace { const PhaseShifterT PShiftLq{}; diff --git a/core/uhjfilter.h b/core/uhjfilter.h index c14ed5bf..d1e0a5eb 100644 --- a/core/uhjfilter.h +++ b/core/uhjfilter.h @@ -13,6 +13,8 @@ static constexpr size_t UhjLengthLq{256}; static constexpr size_t UhjLengthHq{512}; static constexpr size_t UhjLengthStd{UhjLengthLq}; +extern size_t UhjQuality; + struct UhjEncoderBase { virtual ~UhjEncoderBase() = default; diff --git a/core/voice.cpp b/core/voice.cpp index 15230726..4030fc5b 100644 --- a/core/voice.cpp +++ b/core/voice.cpp @@ -854,13 +854,29 @@ void Voice::prepare(DeviceBase *device) if(mFmtChannels == FmtSuperStereo) { - mDecoder = std::make_unique>(); - mDecoderPadding = UhjStereoDecoder::sFilterDelay; + if(UhjQuality >= UhjLengthHq) + { + mDecoder = std::make_unique>(); + mDecoderPadding = UhjStereoDecoder::sFilterDelay; + } + else + { + mDecoder = std::make_unique>(); + mDecoderPadding = UhjStereoDecoder::sFilterDelay; + } } else if(IsUHJ(mFmtChannels)) { - mDecoder = std::make_unique>(); - mDecoderPadding = UhjDecoder::sFilterDelay; + if(UhjQuality >= UhjLengthHq) + { + mDecoder = std::make_unique>(); + mDecoderPadding = UhjDecoder::sFilterDelay; + } + else + { + mDecoder = std::make_unique>(); + mDecoderPadding = UhjDecoder::sFilterDelay; + } } else {