diff options
author | Chris Robinson <[email protected]> | 2019-01-06 00:23:15 -0800 |
---|---|---|
committer | Chris Robinson <[email protected]> | 2019-01-06 00:23:15 -0800 |
commit | 03aeb7edf60e809de26a34f4a44dc2ef90efae71 (patch) | |
tree | 1ed979b92ec6723a120616e40754529631b720e5 | |
parent | 3b91010e21f607196a3927f617164c4fdb68b5e6 (diff) |
Use a shelf filter for the HRTF B-Format decoder HF scale
-rw-r--r-- | Alc/hrtf.cpp | 87 |
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); |