diff options
author | Chris Robinson <[email protected]> | 2019-05-22 10:58:18 -0700 |
---|---|---|
committer | Chris Robinson <[email protected]> | 2019-05-22 11:07:12 -0700 |
commit | 67085040268003b6027317cca64ca72a18d90ce7 (patch) | |
tree | 3fd630d64247a4b86f710b1317e50b7c9a1f5fb5 | |
parent | b48bab33948dae90a27b4f8ccd3eb6b20d49ba86 (diff) |
Properly reverse the HRTF field order when loading it
And combine a couple arrays into an array structure
-rw-r--r-- | Alc/hrtf.cpp | 167 | ||||
-rw-r--r-- | Alc/hrtf.h | 13 |
2 files changed, 108 insertions, 72 deletions
diff --git a/Alc/hrtf.cpp b/Alc/hrtf.cpp index ede8f8c5..bc183d1b 100644 --- a/Alc/hrtf.cpp +++ b/Alc/hrtf.cpp @@ -214,30 +214,29 @@ void GetHrtfCoeffs(const HrtfEntry *Hrtf, ALfloat elevation, ALfloat azimuth, AL const auto *field = Hrtf->field; const auto *field_end = field + Hrtf->fdCount-1; - ALsizei fdoffset{Hrtf->evFarBase}; + ALsizei ebase{0}; while(distance < field->distance && field != field_end) { + ebase += field->evCount; ++field; - fdoffset -= field->evCount; } - assert(fdoffset >= 0); /* Claculate the elevation indinces. */ const auto elev0 = CalcEvIndex(field->evCount, elevation); const ALsizei elev1_idx{mini(elev0.idx+1, field->evCount-1)}; - const ALsizei ev0offset{Hrtf->evOffset[fdoffset + elev0.idx]}; - const ALsizei ev1offset{Hrtf->evOffset[fdoffset + elev1_idx]}; + const ALsizei ir0offset{Hrtf->elev[ebase + elev0.idx].irOffset}; + const ALsizei ir1offset{Hrtf->elev[ebase + elev1_idx].irOffset}; /* Calculate azimuth indices. */ - const auto az0 = CalcAzIndex(Hrtf->azCount[fdoffset + elev0.idx], azimuth); - const auto az1 = CalcAzIndex(Hrtf->azCount[fdoffset + elev1_idx], azimuth); + const auto az0 = CalcAzIndex(Hrtf->elev[ebase + elev0.idx].azCount, azimuth); + const auto az1 = CalcAzIndex(Hrtf->elev[ebase + elev1_idx].azCount, azimuth); /* Calculate the HRIR indices to blend. */ ALsizei idx[4]{ - ev0offset + az0.idx, - ev0offset + ((az0.idx+1) % Hrtf->azCount[fdoffset + elev0.idx]), - ev1offset + az1.idx, - ev1offset + ((az1.idx+1) % Hrtf->azCount[fdoffset + elev1_idx]) + ir0offset + az0.idx, + ir0offset + ((az0.idx+1) % Hrtf->elev[ebase + elev0.idx].azCount), + ir1offset + az1.idx, + ir1offset + ((az1.idx+1) % Hrtf->elev[ebase + elev1_idx].azCount) }; /* Calculate bilinear blending weights, attenuated according to the @@ -307,25 +306,24 @@ void BuildBFormatHrtf(const HrtfEntry *Hrtf, DirectHrtfState *state, const ALsiz ASSUME(AmbiCount > 0); auto &field = Hrtf->field[0]; - const ALsizei ebase{Hrtf->evFarBase}; ALsizei min_delay{HRTF_HISTORY_LENGTH}; ALsizei max_delay{0}; auto idx = al::vector<ALsizei>(AmbiCount); - auto calc_idxs = [Hrtf,ebase,&field,&max_delay,&min_delay](const AngularPoint &pt) noexcept -> ALsizei + auto calc_idxs = [Hrtf,&field,&max_delay,&min_delay](const AngularPoint &pt) noexcept -> ALsizei { /* Calculate elevation index. */ - const auto evidx = ebase + clampi( + const auto evidx = clampi( static_cast<ALsizei>((90.0f+pt.Elev)*(field.evCount-1)/180.0f + 0.5f), 0, field.evCount-1); - const ALsizei azcount{Hrtf->azCount[evidx]}; - const ALsizei evoffset{Hrtf->evOffset[evidx]}; + const ALsizei azcount{Hrtf->elev[evidx].azCount}; + const ALsizei iroffset{Hrtf->elev[evidx].irOffset}; /* Calculate azimuth index for this elevation. */ const auto azidx = static_cast<ALsizei>((360.0f+pt.Azim)*azcount/360.0f + 0.5f) % azcount; /* Calculate the index for the impulse response. */ - ALsizei idx{evoffset + azidx}; + ALsizei idx{iroffset + azidx}; min_delay = mini(min_delay, mini(Hrtf->delays[idx][0], Hrtf->delays[idx][1])); max_delay = maxi(max_delay, maxi(Hrtf->delays[idx][0], Hrtf->delays[idx][1])); @@ -459,8 +457,8 @@ void BuildBFormatHrtf(const HrtfEntry *Hrtf, DirectHrtfState *state, const ALsiz namespace { std::unique_ptr<HrtfEntry> CreateHrtfStore(ALuint rate, ALsizei irSize, const ALsizei fdCount, - const ALubyte *evCount, const ALfloat *distance, const ALubyte *azCount, - const ALushort *evOffset, ALsizei irCount, const ALfloat (*coeffs)[2], + const ALubyte *evCount, const ALfloat *distance, const ALushort *azCount, + const ALushort *irOffset, ALsizei irCount, const ALfloat (*coeffs)[2], const ALubyte (*delays)[2], const char *filename) { std::unique_ptr<HrtfEntry> Hrtf; @@ -469,9 +467,8 @@ std::unique_ptr<HrtfEntry> CreateHrtfStore(ALuint rate, ALsizei irSize, const AL size_t total{sizeof(HrtfEntry)}; total = RoundUp(total, alignof(HrtfEntry::Field)); /* Align for field infos */ total += sizeof(HrtfEntry::Field)*fdCount; - total += sizeof(Hrtf->azCount[0])*evTotal; - total = RoundUp(total, sizeof(ALushort)); /* Align for ushort fields */ - total += sizeof(Hrtf->evOffset[0])*evTotal; + total = RoundUp(total, alignof(HrtfEntry::Elevation)); /* Align for elevation infos */ + total += sizeof(Hrtf->elev[0])*evTotal; total = RoundUp(total, 16); /* Align for coefficients using SIMD */ total += sizeof(Hrtf->coeffs[0])*irSize*irCount; total += sizeof(Hrtf->delays[0])*irCount; @@ -484,7 +481,6 @@ std::unique_ptr<HrtfEntry> CreateHrtfStore(ALuint rate, ALsizei irSize, const AL InitRef(&Hrtf->ref, 1u); Hrtf->sampleRate = rate; Hrtf->irSize = irSize; - Hrtf->evFarBase = std::accumulate(evCount+1, evCount+fdCount, 0); Hrtf->fdCount = fdCount; /* Set up pointers to storage following the main HRTF struct. */ @@ -495,12 +491,9 @@ std::unique_ptr<HrtfEntry> CreateHrtfStore(ALuint rate, ALsizei irSize, const AL auto field_ = reinterpret_cast<HrtfEntry::Field*>(base + offset); offset += sizeof(field_[0])*fdCount; - auto azCount_ = reinterpret_cast<ALubyte*>(base + offset); - offset += sizeof(azCount_[0])*evTotal; - - offset = RoundUp(offset, sizeof(ALushort)); /* Align for ushort fields */ - auto evOffset_ = reinterpret_cast<ALushort*>(base + offset); - offset += sizeof(evOffset_[0])*evTotal; + offset = RoundUp(offset, alignof(HrtfEntry::Elevation)); /* Align for elevation infos */ + auto elev_ = reinterpret_cast<HrtfEntry::Elevation*>(base + offset); + offset += sizeof(elev_[0])*evTotal; offset = RoundUp(offset, 16); /* Align for coefficients using SIMD */ auto coeffs_ = reinterpret_cast<ALfloat(*)[2]>(base + offset); @@ -514,11 +507,14 @@ std::unique_ptr<HrtfEntry> CreateHrtfStore(ALuint rate, ALsizei irSize, const AL /* Copy input data to storage. */ for(ALsizei i{0};i < fdCount;i++) { - field_[i].evCount = evCount[i]; field_[i].distance = distance[i]; + field_[i].evCount = evCount[i]; + } + for(ALsizei i{0};i < evTotal;i++) + { + elev_[i].azCount = azCount[i]; + elev_[i].irOffset = irOffset[i]; } - for(ALsizei i{0};i < evTotal;i++) azCount_[i] = azCount[i]; - for(ALsizei i{0};i < evTotal;i++) evOffset_[i] = evOffset[i]; for(ALsizei i{0};i < irSize*irCount;i++) { coeffs_[i][0] = coeffs[i][0]; @@ -532,8 +528,7 @@ std::unique_ptr<HrtfEntry> CreateHrtfStore(ALuint rate, ALsizei irSize, const AL /* Finally, assign the storage pointers. */ Hrtf->field = field_; - Hrtf->azCount = azCount_; - Hrtf->evOffset = evOffset_; + Hrtf->elev = elev_; Hrtf->coeffs = coeffs_; Hrtf->delays = delays_; } @@ -631,7 +626,7 @@ std::unique_ptr<HrtfEntry> LoadHrtf00(std::istream &data, const char *filename) if(failed) return nullptr; - al::vector<ALubyte> azCount(evCount); + al::vector<ALushort> azCount(evCount); for(ALsizei i{1};i < evCount;i++) { azCount[i-1] = evOffset[i] - evOffset[i-1]; @@ -723,9 +718,9 @@ std::unique_ptr<HrtfEntry> LoadHrtf01(std::istream &data, const char *filename) if(failed) return nullptr; - al::vector<ALubyte> azCount(evCount); - data.read(reinterpret_cast<char*>(azCount.data()), evCount); - if(!data || data.eof() || data.gcount() < evCount) + al::vector<ALushort> azCount(evCount); + std::generate(azCount.begin(), azCount.end(), std::bind(GetLE_ALubyte, std::ref(data))); + if(!data || data.eof()) { ERR("Failed reading %s\n", filename); return nullptr; @@ -843,7 +838,7 @@ std::unique_ptr<HrtfEntry> LoadHrtf02(std::istream &data, const char *filename) al::vector<ALfloat> distance(fdCount); al::vector<ALubyte> evCount(fdCount); - al::vector<ALubyte> azCount; + al::vector<ALushort> azCount; for(ALsizei f{0};f < fdCount;f++) { distance[f] = GetLE_ALushort(data) / 1000.0f; @@ -877,8 +872,9 @@ std::unique_ptr<HrtfEntry> LoadHrtf02(std::istream &data, const char *filename) size_t ebase{azCount.size()}; azCount.resize(ebase + evCount[f]); - data.read(reinterpret_cast<char*>(azCount.data()+ebase), evCount[f]); - if(!data || data.eof() || data.gcount() < evCount[f]) + std::generate(azCount.begin()+ebase, azCount.end(), + std::bind(GetLE_ALubyte, std::ref(data))); + if(!data || data.eof()) { ERR("Failed reading %s\n", filename); return nullptr; @@ -897,31 +893,11 @@ std::unique_ptr<HrtfEntry> LoadHrtf02(std::istream &data, const char *filename) return nullptr; } - al::vector<ALushort> evOffset; - evOffset.resize(evCount[0]); - + al::vector<ALushort> evOffset(azCount.size()); evOffset[0] = 0; - ALushort irCount{azCount[0]}; - for(ALsizei e{1};e < evCount[0];++e) - { - evOffset[e] = evOffset[e-1] + azCount[e-1]; - irCount += azCount[e]; - } - - ALsizei irTotal{irCount}; - for(ALsizei f{1};f < fdCount;f++) - { - const ALsizei ebase{std::accumulate(evCount.begin(), evCount.begin()+f, 0)}; - evOffset.resize(ebase + evCount[f]); + std::partial_sum(azCount.cbegin(), azCount.cend()-1, evOffset.begin()+1); + const ALsizei irTotal{evOffset.back() + azCount.back()}; - evOffset[ebase] = irTotal; - irTotal += azCount[ebase]; - for(ALsizei e{1};e < evCount[f];++e) - { - evOffset[ebase+e] = evOffset[ebase+e-1] + azCount[ebase+e-1]; - irTotal += azCount[ebase+e]; - } - } al::vector<std::array<ALfloat,2>> coeffs(irSize*irTotal); al::vector<std::array<ALubyte,2>> delays(irTotal); if(channelType == CHANTYPE_LEFTONLY) @@ -1022,8 +998,67 @@ std::unique_ptr<HrtfEntry> LoadHrtf02(std::istream &data, const char *filename) } } - std::reverse(distance.begin(), distance.end()); - std::reverse(evCount.begin(), evCount.end()); + if(fdCount > 1) + { + auto distance_ = al::vector<ALfloat>(distance.size()); + auto evCount_ = al::vector<ALubyte>(evCount.size()); + auto azCount_ = al::vector<ALushort>(azCount.size()); + auto evOffset_ = al::vector<ALushort>(evOffset.size()); + auto coeffs_ = al::vector<float2>(coeffs.size()); + auto delays_ = al::vector<std::array<ALubyte,2>>(delays.size()); + + /* Simple reverse for the per-field elements. */ + std::reverse_copy(distance.cbegin(), distance.cend(), distance_.begin()); + std::reverse_copy(evCount.cbegin(), evCount.cend(), evCount_.begin()); + + /* Each field has a group of elevations, which each have an azimuth + * count. Reverse the order of the groups, keeping the relative order + * of per-group azimuth counts. + */ + auto azcnt_end = azCount_.end(); + auto copy_azs = [&azCount,&azcnt_end](const size_t ebase, const ALubyte num_evs) -> size_t + { + auto azcnt_src = azCount.begin()+ebase; + azcnt_end = std::copy_backward(azcnt_src, azcnt_src+num_evs, azcnt_end); + return ebase + num_evs; + }; + std::accumulate(evCount.cbegin(), evCount.cend(), 0u, copy_azs); + assert(azCount_.begin() == azcnt_end); + + /* Reestablish the IR offset for each elevation index, given the new + * ordering of elevations. + */ + evOffset_[0] = 0; + std::partial_sum(azCount_.cbegin(), azCount_.cend()-1, evOffset_.begin()+1); + + /* Reverse the order of each field's group of IRs. */ + auto coeffs_end = coeffs_.end(); + auto delays_end = delays_.end(); + auto copy_irs = [irSize,&azCount,&coeffs,&delays,&coeffs_end,&delays_end](const size_t ebase, const ALubyte num_evs) -> size_t + { + const ALsizei abase{std::accumulate(azCount.cbegin(), azCount.cbegin()+ebase, 0)}; + const ALsizei num_azs{std::accumulate(azCount.cbegin()+ebase, + azCount.cbegin() + (ebase+num_evs), 0)}; + + coeffs_end = std::copy_backward(coeffs.cbegin() + abase*irSize, + coeffs.cbegin() + (abase+num_azs)*irSize, coeffs_end); + delays_end = std::copy_backward(delays.cbegin() + abase, + delays.cbegin() + (abase+num_azs), delays_end); + + return ebase + num_evs; + }; + std::accumulate(evCount.cbegin(), evCount.cend(), 0u, copy_irs); + assert(coeffs_.begin() == coeffs_end); + assert(delays_.begin() == delays_end); + + distance = std::move(distance_); + evCount = std::move(evCount_); + azCount = std::move(azCount_); + evOffset = std::move(evOffset_); + coeffs = std::move(coeffs_); + delays = std::move(delays_); + } + return CreateHrtfStore(rate, irSize, fdCount, evCount.data(), distance.data(), azCount.data(), evOffset.data(), irTotal, &reinterpret_cast<ALfloat(&)[2]>(coeffs[0]), &reinterpret_cast<ALubyte(&)[2]>(delays[0]), filename); @@ -29,20 +29,21 @@ struct HrtfEntry { ALuint sampleRate; ALsizei irSize; - /* Base elevation index for the farthest field. */ - ALsizei evFarBase; struct Field { - ALubyte evCount; ALfloat distance; + ALubyte evCount; }; /* NOTE: Fields are stored *backwards*. field[0] is the farthest field, and * field[fdCount-1] is the nearest. */ ALsizei fdCount; - Field *field; + const Field *field; - const ALubyte *azCount; - const ALushort *evOffset; + struct Elevation { + ALushort azCount; + ALushort irOffset; + }; + Elevation *elev; const ALfloat (*coeffs)[2]; const ALubyte (*delays)[2]; |