Resample HRIRs when loading

This commit is contained in:
Chris Robinson
2019-11-28 11:48:44 -08:00
parent c093728ced
commit f6105cbff0
4 changed files with 56 additions and 44 deletions
+2 -26
View File
@@ -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>();
}
}
+51 -7
View File
@@ -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();
+1 -1
View File
@@ -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]);
+2 -10
View File
@@ -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;