diff options
-rw-r--r-- | Alc/bformatdec.cpp | 93 | ||||
-rw-r--r-- | Alc/bformatdec.h | 5 |
2 files changed, 66 insertions, 32 deletions
diff --git a/Alc/bformatdec.cpp b/Alc/bformatdec.cpp index 08f74d8b..a6c8f4c6 100644 --- a/Alc/bformatdec.cpp +++ b/Alc/bformatdec.cpp @@ -112,8 +112,6 @@ void BFormatDec::reset(const AmbDecConf *conf, ALsizei chancount, ALuint srate, calc_rcpQ_from_slope(gain1, 1.0f)); for(ALsizei i{2};i < 4;i++) mUpSampler[i].Shelf.copyParamsFrom(mUpSampler[1].Shelf); - for(auto &upsampler : mUpSampler) - upsampler.Shelf.clear(); } const bool periphonic{(conf->ChanMask&AMBI_PERIPHONIC_MASK) != 0}; @@ -233,45 +231,78 @@ void AmbiUpsampler::reset(const ALCdevice *device) { const ALfloat xover_norm{400.0f / (float)device->Frequency}; - mInput[0].XOver.init(xover_norm); - for(auto input = std::begin(mInput)+1;input != std::end(mInput);++input) - input->XOver = mInput[0].XOver; - - ALfloat encgains[8][MAX_OUTPUT_CHANNELS]; - for(size_t k{0u};k < COUNTOF(Ambi3DPoints);k++) + mSimpleUp = (device->Dry.CoeffCount == 0); + if(mSimpleUp) { - ALfloat coeffs[MAX_AMBI_COEFFS]; - CalcDirectionCoeffs(Ambi3DPoints[k], 0.0f, coeffs); - ComputePanGains(&device->Dry, coeffs, 1.0f, encgains[k]); - } + const ALfloat (&hfscales)[MAX_AMBI_COEFFS] = GetDecoderHFScales( + (device->Dry.NumChannels > 16) ? 4 : + (device->Dry.NumChannels > 9) ? 3 : + (device->Dry.NumChannels > 4) ? 2 : 1); + const ALfloat gain0{std::sqrt(Ambi3DDecoderHFScale[0] / hfscales[0])}; + const ALfloat gain1{std::sqrt(Ambi3DDecoderHFScale[1] / hfscales[1])}; - /* Combine the matrices that do the in->virt and virt->out conversions so - * we get a single in->out conversion. NOTE: the Encoder matrix (encgains) - * and output are transposed, so the input channels line up with the rows - * and the output channels line up with the columns. - */ - const ALfloat (&hfscales)[MAX_AMBI_COEFFS] = GetDecoderHFScales( - (device->Dry.NumChannels > 16) ? 4 : - (device->Dry.NumChannels > 9) ? 3 : - (device->Dry.NumChannels > 4) ? 2 : 1); - for(ALsizei i{0};i < 4;i++) + mShelf[0].setParams(BiquadType::HighShelf, gain0, xover_norm, + calc_rcpQ_from_slope(gain0, 1.0f)); + mShelf[1].setParams(BiquadType::HighShelf, gain1, xover_norm, + calc_rcpQ_from_slope(gain1, 1.0f)); + for(ALsizei i{2};i < 4;i++) + mShelf[i].copyParamsFrom(mShelf[1]); + } + else { - mInput[i].Gains.fill({}); - const ALdouble hfscale = static_cast<ALdouble>(Ambi3DDecoderHFScale[i]) / hfscales[i]; - for(ALsizei j{0};j < device->Dry.NumChannels;j++) + mInput[0].XOver.init(xover_norm); + for(auto input = std::begin(mInput)+1;input != std::end(mInput);++input) + input->XOver = mInput[0].XOver; + + ALfloat encgains[8][MAX_OUTPUT_CHANNELS]; + for(size_t k{0u};k < COUNTOF(Ambi3DPoints);k++) + { + ALfloat coeffs[MAX_AMBI_COEFFS]; + CalcDirectionCoeffs(Ambi3DPoints[k], 0.0f, coeffs); + ComputePanGains(&device->Dry, coeffs, 1.0f, encgains[k]); + } + + /* Combine the matrices that do the in->virt and virt->out conversions + * so we get a single in->out conversion. NOTE: the Encoder matrix + * (encgains) and output are transposed, so the input channels line up + * with the rows and the output channels line up with the columns. + */ + const ALfloat (&hfscales)[MAX_AMBI_COEFFS] = GetDecoderHFScales( + (device->Dry.CoeffCount > 16) ? 4 : + (device->Dry.CoeffCount > 9) ? 3 : + (device->Dry.CoeffCount > 4) ? 2 : 1); + for(ALsizei i{0};i < 4;i++) { - ALdouble gain{0.0}; - for(size_t k{0u};k < COUNTOF(Ambi3DDecoder);k++) - gain += (ALdouble)Ambi3DDecoder[k][i] * encgains[k][j]; - mInput[i].Gains[HF_BAND][j] = (ALfloat)(gain * hfscale); - mInput[i].Gains[LF_BAND][j] = (ALfloat)gain; + mInput[i].Gains.fill({}); + const ALdouble hfscale = static_cast<ALdouble>(Ambi3DDecoderHFScale[i]) / hfscales[i]; + for(ALsizei j{0};j < device->Dry.NumChannels;j++) + { + ALdouble gain{0.0}; + for(size_t k{0u};k < COUNTOF(Ambi3DDecoder);k++) + gain += (ALdouble)Ambi3DDecoder[k][i] * encgains[k][j]; + mInput[i].Gains[HF_BAND][j] = (ALfloat)(gain * hfscale); + mInput[i].Gains[LF_BAND][j] = (ALfloat)gain; + } } } } void AmbiUpsampler::process(ALfloat (*OutBuffer)[BUFFERSIZE], const ALsizei OutChannels, const ALfloat (*InSamples)[BUFFERSIZE], const ALsizei SamplesToDo) { - for(auto input = std::begin(mInput);input != std::end(mInput);++input) + ASSUME(SamplesToDo > 0); + + if(mSimpleUp) + { + for(ALsizei i{0};i < 4;i++) + { + mShelf[i].process(mSamples[0], InSamples[i], SamplesToDo); + + const ALfloat *RESTRICT src{al::assume_aligned<16>(mSamples[0])}; + ALfloat *dst{al::assume_aligned<16>(OutBuffer[i])}; + std::transform(src, src+SamplesToDo, dst, dst, std::plus<float>{}); + } + } + else for(auto input = std::begin(mInput);input != std::end(mInput);++input) { input->XOver.process(mSamples[HF_BAND], mSamples[LF_BAND], *(InSamples++), SamplesToDo); diff --git a/Alc/bformatdec.h b/Alc/bformatdec.h index 9c7ce7a7..144c22a2 100644 --- a/Alc/bformatdec.h +++ b/Alc/bformatdec.h @@ -51,7 +51,8 @@ public: /* Stand-alone first-order upsampler. Kept here because it shares some stuff - * with bformatdec. Assumes a periphonic (4-channel) input mix! + * with bformatdec. Assumes a periphonic (4-channel) input mix! If output is + * B-Format, it must also be periphonic. */ class AmbiUpsampler { public: @@ -60,6 +61,8 @@ public: private: alignas(16) ALfloat mSamples[sNumBands][BUFFERSIZE]; + bool mSimpleUp; + BiquadFilter mShelf[4]; struct { BandSplitter XOver; std::array<std::array<ALfloat,MAX_OUTPUT_CHANNELS>,sNumBands> Gains; |