aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChris Robinson <[email protected]>2019-01-06 00:23:15 -0800
committerChris Robinson <[email protected]>2019-01-06 00:23:15 -0800
commit03aeb7edf60e809de26a34f4a44dc2ef90efae71 (patch)
tree1ed979b92ec6723a120616e40754529631b720e5
parent3b91010e21f607196a3927f617164c4fdb68b5e6 (diff)
Use a shelf filter for the HRTF B-Format decoder HF scale
-rw-r--r--Alc/hrtf.cpp87
1 files changed, 50 insertions, 37 deletions
diff --git a/Alc/hrtf.cpp b/Alc/hrtf.cpp
index 2cdabc2a..50c5c459 100644
--- a/Alc/hrtf.cpp
+++ b/Alc/hrtf.cpp
@@ -37,7 +37,7 @@
#include "alu.h"
#include "hrtf.h"
#include "alconfig.h"
-#include "filters/splitter.h"
+#include "filters/biquad.h"
#include "compat.h"
#include "almalloc.h"
@@ -278,15 +278,15 @@ void BuildBFormatHrtf(const HrtfEntry *Hrtf, DirectHrtfState *state, const ALsiz
static constexpr int OrderFromChan[MAX_AMBI_COEFFS]{
0, 1,1,1, 2,2,2,2,2, 3,3,3,3,3,3,3,
};
+ /* Set this to true for dual-band HRTF processing. May require a higher
+ * quality filter, or better calculation of the new IR length to deal with
+ * the tail generated by the filter.
+ */
+ static constexpr bool DualBand{true};
ASSUME(NumChannels > 0);
ASSUME(AmbiCount > 0);
-/* Set this to 2 for dual-band HRTF processing. May require a higher quality
- * band-splitter, or better calculation of the new IR length to deal with the
- * tail generated by the filter.
- */
-#define NUM_BANDS 2
ALsizei min_delay{HRTF_HISTORY_LENGTH};
ALsizei max_delay{0};
al::vector<ALsizei> idx(AmbiCount);
@@ -313,16 +313,24 @@ void BuildBFormatHrtf(const HrtfEntry *Hrtf, DirectHrtfState *state, const ALsiz
};
std::transform(AmbiPoints, AmbiPoints+AmbiCount, idx.begin(), calc_idxs);
+ const ALfloat xover_norm{400.0f / (ALfloat)Hrtf->sampleRate};
+ const ALsizei order_limit{OrderFromChan[NumChannels-1] + 1};
+ BiquadFilter shelf[MAX_AMBI_ORDER+1];
+ for(ALsizei o{0};o < order_limit;++o)
+ {
+ const ALfloat g{std::sqrt(AmbiOrderHFGain[o])};
+ shelf[o].setParams(BiquadType::HighShelf, g, xover_norm, calc_rcpQ_from_slope(g, 1.0f));
+ }
+
al::vector<std::array<std::array<ALdouble,2>,HRIR_LENGTH>> tmpres(NumChannels);
- BandSplitter splitter;
- splitter.init(400.0f / (ALfloat)Hrtf->sampleRate);
+ al::vector<std::array<ALfloat,HRIR_LENGTH>> tmpfilt(order_limit+1);
for(ALsizei c{0};c < AmbiCount;++c)
{
const ALfloat (*fir)[2]{&Hrtf->coeffs[idx[c] * Hrtf->irSize]};
- ALsizei ldelay{Hrtf->delays[idx[c]][0] - min_delay};
- ALsizei rdelay{Hrtf->delays[idx[c]][1] - min_delay};
+ const ALsizei ldelay{Hrtf->delays[idx[c]][0] - min_delay};
+ const ALsizei rdelay{Hrtf->delays[idx[c]][1] - min_delay};
- if(NUM_BANDS == 1)
+ if(!DualBand)
{
for(ALsizei i{0};i < NumChannels;++i)
{
@@ -338,45 +346,50 @@ void BuildBFormatHrtf(const HrtfEntry *Hrtf, DirectHrtfState *state, const ALsiz
}
else
{
- ALfloat temps[3][HRIR_LENGTH]{};
-
- /* Band-split left HRIR into low and high frequency responses. */
- splitter.clear();
- std::transform(fir, fir+Hrtf->irSize, std::begin(temps[2]),
+ /* Extract the left HRIR and increase its per-order high-frequency
+ * response.
+ */
+ auto tmpfilt_iter = std::transform(fir, fir+Hrtf->irSize, tmpfilt.back().begin(),
[](const ALfloat (&ir)[2]) noexcept { return ir[0]; });
- splitter.process(temps[0], temps[1], temps[2], HRIR_LENGTH);
+ std::fill(tmpfilt_iter, tmpfilt.back().end(), 0.0f);
+ for(ALsizei o{0};o < order_limit;++o)
+ {
+ shelf[o].clear();
+ shelf[o].process(tmpfilt[o].data(), tmpfilt.back().data(), HRIR_LENGTH);
+ }
/* Apply left ear response with delay. */
for(ALsizei i{0};i < NumChannels;++i)
{
- const ALdouble hfgain{AmbiOrderHFGain[OrderFromChan[i]]};
- for(ALsizei b{0};b < NUM_BANDS;++b)
- {
- const ALdouble mult{AmbiMatrix[c][i] * ((b==0) ? hfgain : 1.0)};
- for(ALsizei lidx{ldelay},j{0};lidx < HRIR_LENGTH;++lidx,++j)
- tmpres[i][lidx][0] += temps[b][j] * mult;
- }
+ const ALsizei order{OrderFromChan[i]};
+ const ALdouble mult{AmbiMatrix[c][i]};
+ for(ALsizei lidx{ldelay},j{0};lidx < HRIR_LENGTH;++lidx,++j)
+ tmpres[i][lidx][0] += tmpfilt[order][j] * mult;
}
- /* Band-split right HRIR into low and high frequency responses. */
- splitter.clear();
- std::transform(fir, fir+Hrtf->irSize, std::begin(temps[2]),
+ /* Extract the right HRIR and increase its per-order high-frequency
+ * response.
+ */
+ tmpfilt_iter = std::transform(fir, fir+Hrtf->irSize, tmpfilt.back().begin(),
[](const ALfloat (&ir)[2]) noexcept { return ir[1]; });
- splitter.process(temps[0], temps[1], temps[2], HRIR_LENGTH);
+ std::fill(tmpfilt_iter, tmpfilt.back().end(), 0.0f);
+ for(ALsizei o{0};o < order_limit;++o)
+ {
+ shelf[o].clear();
+ shelf[o].process(tmpfilt[o].data(), tmpfilt.back().data(), HRIR_LENGTH);
+ }
/* Apply right ear response with delay. */
for(ALsizei i{0};i < NumChannels;++i)
{
- const ALdouble hfgain{AmbiOrderHFGain[OrderFromChan[i]]};
- for(ALsizei b{0};b < NUM_BANDS;++b)
- {
- const ALdouble mult{AmbiMatrix[c][i] * ((b==0) ? hfgain : 1.0)};
- for(ALsizei ridx{rdelay},j{0};ridx < HRIR_LENGTH;++ridx,++j)
- tmpres[i][ridx][1] += temps[b][j] * mult;
- }
+ const ALsizei order{OrderFromChan[i]};
+ const ALdouble mult{AmbiMatrix[c][i]};
+ for(ALsizei ridx{rdelay},j{0};ridx < HRIR_LENGTH;++ridx,++j)
+ tmpres[i][ridx][1] += tmpfilt[order][j] * mult;
}
}
}
+ tmpfilt.clear();
for(ALsizei i{0};i < NumChannels;++i)
{
@@ -390,12 +403,12 @@ void BuildBFormatHrtf(const HrtfEntry *Hrtf, DirectHrtfState *state, const ALsiz
idx.clear();
ALsizei max_length;
- if(NUM_BANDS == 1)
+ if(!DualBand)
max_length = mini(max_delay-min_delay + Hrtf->irSize, HRIR_LENGTH);
else
{
/* Increase the IR size by 2/3rds to account for the tail generated by
- * the band-split filter.
+ * the filter.
*/
const ALsizei irsize = mini(Hrtf->irSize*5/3, HRIR_LENGTH);
max_length = mini(max_delay-min_delay + irsize, HRIR_LENGTH);