aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChris Robinson <[email protected]>2019-11-28 11:48:44 -0800
committerChris Robinson <[email protected]>2019-11-28 12:33:26 -0800
commitf6105cbff044e929c3c6edd9c79a69c1fff7b399 (patch)
tree00cc84b985e48fdec7431dfdc3eef9f2d256c992
parentc093728ced2da0eb5fb01235c62460262b704790 (diff)
Resample HRIRs when loading
-rw-r--r--alc/alc.cpp28
-rw-r--r--alc/hrtf.cpp58
-rw-r--r--alc/hrtf.h2
-rw-r--r--alc/panning.cpp12
4 files changed, 56 insertions, 44 deletions
diff --git a/alc/alc.cpp b/alc/alc.cpp
index 4557771f..0a90a14f 100644
--- a/alc/alc.cpp
+++ b/alc/alc.cpp
@@ -1888,32 +1888,8 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList)
if(hrtf_userreq == Hrtf_Enable || (hrtf_userreq != Hrtf_Disable && hrtf_appreq == Hrtf_Enable))
{
- HrtfStore *hrtf{nullptr};
- if(device->HrtfList.empty())
- device->HrtfList = EnumerateHrtf(device->DeviceName.c_str());
- if(!device->HrtfList.empty())
- {
- if(hrtf_id >= 0 && static_cast<ALuint>(hrtf_id) < device->HrtfList.size())
- hrtf = GetLoadedHrtf(device->HrtfList[static_cast<ALuint>(hrtf_id)]);
- else
- hrtf = GetLoadedHrtf(device->HrtfList.front());
- }
-
- if(hrtf)
- {
- device->FmtChans = DevFmtStereo;
- device->Frequency = hrtf->sampleRate;
- device->Flags.set<ChannelsRequest, FrequencyRequest>();
- if(HrtfStore *oldhrtf{device->mHrtf})
- oldhrtf->DecRef();
- device->mHrtf = hrtf;
- }
- else
- {
- hrtf_userreq = Hrtf_Default;
- hrtf_appreq = Hrtf_Disable;
- device->HrtfStatus = ALC_HRTF_UNSUPPORTED_FORMAT_SOFT;
- }
+ device->FmtChans = DevFmtStereo;
+ device->Flags.set<ChannelsRequest>();
}
}
diff --git a/alc/hrtf.cpp b/alc/hrtf.cpp
index b02e5e41..b66bbe7f 100644
--- a/alc/hrtf.cpp
+++ b/alc/hrtf.cpp
@@ -52,6 +52,7 @@
#include "logging.h"
#include "math_defs.h"
#include "opthelpers.h"
+#include "polyphase_resampler.h"
namespace {
@@ -1270,7 +1271,7 @@ al::vector<std::string> EnumerateHrtf(const char *devname)
return list;
}
-HrtfStore *GetLoadedHrtf(const std::string &name)
+HrtfStore *GetLoadedHrtf(const std::string &name, ALuint devrate)
{
std::lock_guard<std::mutex> _{EnumeratedHrtfLock};
auto entry_iter = std::find_if(EnumeratedHrtfs.cbegin(), EnumeratedHrtfs.cend(),
@@ -1284,17 +1285,23 @@ HrtfStore *GetLoadedHrtf(const std::string &name)
auto handle = std::find_if(LoadedHrtfs.begin(), LoadedHrtfs.end(),
[&fname](LoadedHrtf &hrtf) -> bool { return hrtf.mFilename == fname; }
);
- if(handle != LoadedHrtfs.end() && handle->mEntry)
+ if(handle != LoadedHrtfs.end())
{
- HrtfStore *hrtf{handle->mEntry.get()};
- hrtf->IncRef();
- return hrtf;
+ do {
+ HrtfStore *hrtf{handle->mEntry.get()};
+ if(hrtf && hrtf->sampleRate == devrate)
+ {
+ hrtf->IncRef();
+ return hrtf;
+ }
+ ++handle;
+ } while(handle != LoadedHrtfs.end() && handle->mFilename == fname);
}
std::unique_ptr<std::istream> stream;
ALint residx{};
char ch{};
- if(sscanf(entry_iter->mFilename.c_str(), "!%d%c", &residx, &ch) == 2 && ch == '_')
+ if(sscanf(fname.c_str(), "!%d%c", &residx, &ch) == 2 && ch == '_')
{
TRACE("Loading %s...\n", fname.c_str());
ResData res{GetResource(residx)};
@@ -1347,7 +1354,44 @@ HrtfStore *GetLoadedHrtf(const std::string &name)
return nullptr;
}
- TRACE("Loaded HRTF support for sample rate: %uhz\n", hrtf->sampleRate);
+ if(hrtf->sampleRate != devrate)
+ {
+ /* Calculate the last elevation's index and get the total IR count. */
+ const size_t lastEv{std::accumulate(hrtf->field, hrtf->field+hrtf->fdCount, size_t{0},
+ [](const size_t curval, const HrtfStore::Field &field) noexcept -> size_t
+ { return curval + field.evCount; }
+ ) - 1};
+ const size_t irCount{size_t{hrtf->elev[lastEv].irOffset} + hrtf->elev[lastEv].azCount};
+
+ /* Resample all the IRs. */
+ std::array<std::array<double,HRIR_LENGTH>,2> inout;
+ PPhaseResampler rs;
+ rs.init(hrtf->sampleRate, devrate);
+ for(size_t i{0};i < irCount;++i)
+ {
+ for(size_t j{0};j < 2;++j)
+ {
+ HrirArray &coeffs = const_cast<HrirArray&>(hrtf->coeffs[i]);
+ std::transform(coeffs.cbegin(), coeffs.cend(), inout[0].begin(),
+ [j](const float2 &in) noexcept -> double { return in[j]; });
+ rs.process(HRIR_LENGTH, inout[0].data(), HRIR_LENGTH, inout[1].data());
+ for(size_t k{0};k < HRIR_LENGTH;++k)
+ coeffs[k][j] = static_cast<float>(inout[1][k]);
+ }
+ }
+
+ /* Scale the IR size for the new sample rate and update the stored
+ * sample rate.
+ */
+ const uint64_t irSize{(uint64_t{hrtf->irSize}*devrate + hrtf->sampleRate-1) /
+ hrtf->sampleRate};
+ hrtf->irSize = static_cast<ALuint>(minu64(HRIR_LENGTH, irSize) + (MOD_IR_SIZE-1));
+ hrtf->irSize -= hrtf->irSize % MOD_IR_SIZE;
+ hrtf->sampleRate = devrate;
+ }
+
+ TRACE("Loaded HRTF %s for sample rate %uhz, %u-sample filter\n", name.c_str(),
+ hrtf->sampleRate, hrtf->irSize);
LoadedHrtfs.emplace_back(LoadedHrtf{fname, std::move(hrtf)});
return LoadedHrtfs.back().mEntry.get();
diff --git a/alc/hrtf.h b/alc/hrtf.h
index 41bee19a..46160409 100644
--- a/alc/hrtf.h
+++ b/alc/hrtf.h
@@ -89,7 +89,7 @@ struct AngularPoint {
al::vector<std::string> EnumerateHrtf(const char *devname);
-HrtfStore *GetLoadedHrtf(const std::string &name);
+HrtfStore *GetLoadedHrtf(const std::string &name, ALuint devrate);
void GetHrtfCoeffs(const HrtfStore *Hrtf, ALfloat elevation, ALfloat azimuth, ALfloat distance,
ALfloat spread, HrirArray &coeffs, ALsizei (&delays)[2]);
diff --git a/alc/panning.cpp b/alc/panning.cpp
index 9cbb60cc..0cf91ac1 100644
--- a/alc/panning.cpp
+++ b/alc/panning.cpp
@@ -813,27 +813,19 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, HrtfRequestMode hrtf_appr
if(hrtf_id >= 0 && static_cast<ALuint>(hrtf_id) < device->HrtfList.size())
{
const std::string &hrtfname = device->HrtfList[static_cast<ALuint>(hrtf_id)];
- HrtfStore *hrtf{GetLoadedHrtf(hrtfname)};
- if(hrtf && hrtf->sampleRate == device->Frequency)
+ if(HrtfStore *hrtf{GetLoadedHrtf(hrtfname, device->Frequency)})
{
device->mHrtf = hrtf;
device->HrtfName = hrtfname;
}
- else if(hrtf)
- hrtf->DecRef();
}
if(!device->mHrtf)
{
auto find_hrtf = [device](const std::string &hrtfname) -> bool
{
- HrtfStore *hrtf{GetLoadedHrtf(hrtfname)};
+ HrtfStore *hrtf{GetLoadedHrtf(hrtfname, device->Frequency)};
if(!hrtf) return false;
- if(hrtf->sampleRate != device->Frequency)
- {
- hrtf->DecRef();
- return false;
- }
device->mHrtf = hrtf;
device->HrtfName = hrtfname;
return true;