diff options
author | Chris Robinson <[email protected]> | 2019-11-28 11:48:44 -0800 |
---|---|---|
committer | Chris Robinson <[email protected]> | 2019-11-28 12:33:26 -0800 |
commit | f6105cbff044e929c3c6edd9c79a69c1fff7b399 (patch) | |
tree | 00cc84b985e48fdec7431dfdc3eef9f2d256c992 | |
parent | c093728ced2da0eb5fb01235c62460262b704790 (diff) |
Resample HRIRs when loading
-rw-r--r-- | alc/alc.cpp | 28 | ||||
-rw-r--r-- | alc/hrtf.cpp | 58 | ||||
-rw-r--r-- | alc/hrtf.h | 2 | ||||
-rw-r--r-- | alc/panning.cpp | 12 |
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(); @@ -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; |