2016-03-15 05:08:05 -07:00
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
|
2019-07-28 11:28:36 -07:00
|
|
|
#include "bformatdec.h"
|
|
|
|
|
|
|
|
#include <algorithm>
|
2018-11-03 18:00:05 -07:00
|
|
|
#include <array>
|
2019-07-28 11:28:36 -07:00
|
|
|
#include <cassert>
|
|
|
|
#include <cmath>
|
|
|
|
#include <iterator>
|
2018-12-08 01:32:43 -08:00
|
|
|
#include <numeric>
|
2018-11-03 18:00:05 -07:00
|
|
|
|
2019-07-28 11:28:36 -07:00
|
|
|
#include "almalloc.h"
|
|
|
|
#include "alu.h"
|
2016-03-15 05:08:05 -07:00
|
|
|
#include "ambdec.h"
|
2018-04-21 23:23:46 -07:00
|
|
|
#include "filters/splitter.h"
|
2019-07-28 11:28:36 -07:00
|
|
|
#include "opthelpers.h"
|
2016-03-23 12:53:36 -07:00
|
|
|
|
2016-03-15 05:08:05 -07:00
|
|
|
|
2018-11-03 18:00:05 -07:00
|
|
|
namespace {
|
|
|
|
|
2019-01-05 21:55:14 -08:00
|
|
|
constexpr ALfloat Ambi3DDecoderHFScale[MAX_AMBI_ORDER+1] = {
|
2019-01-06 17:45:44 -08:00
|
|
|
1.00000000e+00f, 1.00000000e+00f
|
2016-07-30 09:29:21 -07:00
|
|
|
};
|
2019-01-05 21:55:14 -08:00
|
|
|
constexpr ALfloat Ambi3DDecoderHFScale2O[MAX_AMBI_ORDER+1] = {
|
2019-01-06 17:45:44 -08:00
|
|
|
7.45355990e-01f, 1.00000000e+00f
|
2018-02-12 21:24:58 -08:00
|
|
|
};
|
2019-01-05 21:55:14 -08:00
|
|
|
constexpr ALfloat Ambi3DDecoderHFScale3O[MAX_AMBI_ORDER+1] = {
|
2019-01-06 17:45:44 -08:00
|
|
|
5.89792205e-01f, 8.79693856e-01f
|
2018-12-23 10:37:07 -08:00
|
|
|
};
|
2016-03-23 12:53:36 -07:00
|
|
|
|
2019-01-05 21:55:14 -08:00
|
|
|
inline auto GetDecoderHFScales(ALsizei order) noexcept -> const ALfloat(&)[MAX_AMBI_ORDER+1]
|
2018-12-23 10:37:07 -08:00
|
|
|
{
|
|
|
|
if(order >= 3) return Ambi3DDecoderHFScale3O;
|
|
|
|
if(order == 2) return Ambi3DDecoderHFScale2O;
|
|
|
|
return Ambi3DDecoderHFScale;
|
|
|
|
}
|
2016-03-23 12:53:36 -07:00
|
|
|
|
2019-02-19 15:39:33 -08:00
|
|
|
inline auto GetAmbiScales(AmbDecScale scaletype) noexcept -> const std::array<float,MAX_AMBI_CHANNELS>&
|
2018-12-10 22:32:10 -08:00
|
|
|
{
|
2018-12-20 02:46:59 -08:00
|
|
|
if(scaletype == AmbDecScale::FuMa) return AmbiScale::FromFuMa;
|
|
|
|
if(scaletype == AmbDecScale::SN3D) return AmbiScale::FromSN3D;
|
|
|
|
return AmbiScale::FromN3D;
|
2018-12-10 22:32:10 -08:00
|
|
|
}
|
|
|
|
|
2018-11-03 18:00:05 -07:00
|
|
|
} // namespace
|
|
|
|
|
|
|
|
|
2019-06-05 19:26:54 -07:00
|
|
|
BFormatDec::BFormatDec(const AmbDecConf *conf, const bool allow_2band, const ALuint inchans,
|
2019-02-23 00:01:38 -08:00
|
|
|
const ALuint srate, const ALsizei (&chanmap)[MAX_OUTPUT_CHANNELS])
|
2016-03-15 05:08:05 -07:00
|
|
|
{
|
2019-01-05 19:21:25 -08:00
|
|
|
mDualBand = allow_2band && (conf->FreqBands == 2);
|
|
|
|
if(!mDualBand)
|
2019-01-06 05:15:11 -08:00
|
|
|
mSamples.resize(2);
|
2019-01-05 19:21:25 -08:00
|
|
|
else
|
|
|
|
{
|
2019-02-23 00:01:38 -08:00
|
|
|
ASSUME(inchans > 0);
|
2019-01-05 19:21:25 -08:00
|
|
|
mSamples.resize(inchans * 2);
|
|
|
|
mSamplesHF = mSamples.data();
|
|
|
|
mSamplesLF = mSamplesHF + inchans;
|
|
|
|
}
|
|
|
|
mNumChannels = inchans;
|
2016-03-15 05:08:05 -07:00
|
|
|
|
2018-12-15 02:42:04 -08:00
|
|
|
mEnabled = std::accumulate(std::begin(chanmap), std::begin(chanmap)+conf->Speakers.size(), 0u,
|
2018-12-08 01:32:43 -08:00
|
|
|
[](ALuint mask, const ALsizei &chan) noexcept -> ALuint
|
|
|
|
{ return mask | (1 << chan); }
|
|
|
|
);
|
2016-03-28 14:50:18 -07:00
|
|
|
|
2019-01-08 19:42:44 +01:00
|
|
|
const ALfloat xover_norm{conf->XOverFreq / static_cast<float>(srate)};
|
2017-01-24 19:03:51 -08:00
|
|
|
|
2019-01-04 22:17:30 -08:00
|
|
|
const bool periphonic{(conf->ChanMask&AMBI_PERIPHONIC_MASK) != 0};
|
2019-02-19 15:39:33 -08:00
|
|
|
const std::array<float,MAX_AMBI_CHANNELS> &coeff_scale = GetAmbiScales(conf->CoeffScale);
|
2019-02-21 04:05:49 -08:00
|
|
|
const size_t coeff_count{periphonic ? MAX_AMBI_CHANNELS : MAX_AMBI2D_CHANNELS};
|
2018-12-10 21:30:22 -08:00
|
|
|
|
2018-12-13 22:48:02 -08:00
|
|
|
if(!mDualBand)
|
2016-03-15 05:08:05 -07:00
|
|
|
{
|
2018-12-15 02:42:04 -08:00
|
|
|
for(size_t i{0u};i < conf->Speakers.size();i++)
|
2016-07-17 00:29:02 -07:00
|
|
|
{
|
2019-02-19 15:39:33 -08:00
|
|
|
ALfloat (&mtx)[MAX_AMBI_CHANNELS] = mMatrix.Single[chanmap[i]];
|
2019-02-21 04:05:49 -08:00
|
|
|
for(size_t j{0},k{0};j < coeff_count;j++)
|
2016-07-17 00:29:02 -07:00
|
|
|
{
|
2019-02-21 04:05:49 -08:00
|
|
|
const size_t l{periphonic ? j : AmbiIndex::From2D[j]};
|
|
|
|
if(!(conf->ChanMask&(1u<<l))) continue;
|
2018-12-13 22:48:02 -08:00
|
|
|
mtx[j] = conf->HFMatrix[i][k] / coeff_scale[l] *
|
|
|
|
((l>=9) ? conf->HFOrderGain[3] :
|
|
|
|
(l>=4) ? conf->HFOrderGain[2] :
|
|
|
|
(l>=1) ? conf->HFOrderGain[1] : conf->HFOrderGain[0]);
|
|
|
|
++k;
|
2016-07-17 00:29:02 -07:00
|
|
|
}
|
|
|
|
}
|
2016-03-15 05:08:05 -07:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2019-01-04 22:17:30 -08:00
|
|
|
mXOver[0].init(xover_norm);
|
2018-12-08 04:10:45 -08:00
|
|
|
std::fill(std::begin(mXOver)+1, std::end(mXOver), mXOver[0]);
|
2016-03-15 05:08:05 -07:00
|
|
|
|
2018-12-10 21:30:22 -08:00
|
|
|
const float ratio{std::pow(10.0f, conf->XOverRatio / 40.0f)};
|
2018-12-15 02:42:04 -08:00
|
|
|
for(size_t i{0u};i < conf->Speakers.size();i++)
|
2016-03-15 05:08:05 -07:00
|
|
|
{
|
2019-02-19 15:39:33 -08:00
|
|
|
ALfloat (&mtx)[sNumBands][MAX_AMBI_CHANNELS] = mMatrix.Dual[chanmap[i]];
|
2019-02-21 04:05:49 -08:00
|
|
|
for(size_t j{0},k{0};j < coeff_count;j++)
|
2016-03-25 19:57:25 -07:00
|
|
|
{
|
2019-02-21 04:05:49 -08:00
|
|
|
const size_t l{periphonic ? j : AmbiIndex::From2D[j]};
|
|
|
|
if(!(conf->ChanMask&(1u<<l))) continue;
|
2019-01-07 21:48:48 -08:00
|
|
|
mtx[sHFBand][j] = conf->HFMatrix[i][k] / coeff_scale[l] *
|
2018-12-13 22:48:02 -08:00
|
|
|
((l>=9) ? conf->HFOrderGain[3] :
|
|
|
|
(l>=4) ? conf->HFOrderGain[2] :
|
|
|
|
(l>=1) ? conf->HFOrderGain[1] : conf->HFOrderGain[0]) * ratio;
|
2019-01-07 21:48:48 -08:00
|
|
|
mtx[sLFBand][j] = conf->LFMatrix[i][k] / coeff_scale[l] *
|
2018-12-13 22:48:02 -08:00
|
|
|
((l>=9) ? conf->LFOrderGain[3] :
|
|
|
|
(l>=4) ? conf->LFOrderGain[2] :
|
|
|
|
(l>=1) ? conf->LFOrderGain[1] : conf->LFOrderGain[0]) / ratio;
|
|
|
|
++k;
|
2016-03-15 05:08:05 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-05 19:26:54 -07:00
|
|
|
BFormatDec::BFormatDec(const ALuint inchans, const ALsizei chancount,
|
2019-02-23 00:01:38 -08:00
|
|
|
const ChannelDec (&chancoeffs)[MAX_OUTPUT_CHANNELS],
|
|
|
|
const ALsizei (&chanmap)[MAX_OUTPUT_CHANNELS])
|
2019-01-05 19:21:25 -08:00
|
|
|
{
|
2019-01-06 05:15:11 -08:00
|
|
|
mSamples.resize(2);
|
2019-01-05 19:21:25 -08:00
|
|
|
mNumChannels = inchans;
|
|
|
|
|
2019-02-23 00:01:38 -08:00
|
|
|
ASSUME(chancount > 0);
|
2019-01-05 19:21:25 -08:00
|
|
|
mEnabled = std::accumulate(std::begin(chanmap), std::begin(chanmap)+chancount, 0u,
|
|
|
|
[](ALuint mask, const ALsizei &chan) noexcept -> ALuint
|
|
|
|
{ return mask | (1 << chan); }
|
|
|
|
);
|
|
|
|
|
2019-03-17 14:03:21 -07:00
|
|
|
const ChannelDec *incoeffs{chancoeffs};
|
|
|
|
auto set_coeffs = [this,inchans,&incoeffs](const ALsizei chanidx) noexcept -> void
|
2019-01-05 19:21:25 -08:00
|
|
|
{
|
2019-02-23 00:01:38 -08:00
|
|
|
ASSUME(chanidx >= 0);
|
|
|
|
ALfloat (&mtx)[MAX_AMBI_CHANNELS] = mMatrix.Single[chanidx];
|
2019-03-17 14:03:21 -07:00
|
|
|
const ALfloat (&coeffs)[MAX_AMBI_CHANNELS] = *(incoeffs++);
|
2019-01-05 19:21:25 -08:00
|
|
|
|
2019-02-23 00:01:38 -08:00
|
|
|
ASSUME(inchans > 0);
|
2019-01-05 19:21:25 -08:00
|
|
|
std::copy_n(std::begin(coeffs), inchans, std::begin(mtx));
|
2019-02-23 00:01:38 -08:00
|
|
|
};
|
|
|
|
std::for_each(chanmap, chanmap+chancount, set_coeffs);
|
2019-01-05 19:21:25 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-07-03 22:59:29 -07:00
|
|
|
void BFormatDec::process(const al::span<FloatBufferLine> OutBuffer,
|
2019-06-05 18:54:17 -07:00
|
|
|
const FloatBufferLine *InSamples, const ALsizei SamplesToDo)
|
2016-03-15 05:08:05 -07:00
|
|
|
{
|
2018-12-08 02:50:34 -08:00
|
|
|
if(mDualBand)
|
2016-03-15 05:08:05 -07:00
|
|
|
{
|
2019-06-05 19:26:54 -07:00
|
|
|
for(ALuint i{0};i < mNumChannels;i++)
|
2019-05-28 16:22:36 -07:00
|
|
|
mXOver[i].process(mSamplesHF[i].data(), mSamplesLF[i].data(), InSamples[i].data(),
|
|
|
|
SamplesToDo);
|
2016-03-15 05:08:05 -07:00
|
|
|
|
2019-06-05 19:26:54 -07:00
|
|
|
const al::span<const FloatBufferLine> hfsamples{mSamplesHF, mNumChannels};
|
|
|
|
const al::span<const FloatBufferLine> lfsamples{mSamplesLF, mNumChannels};
|
2019-07-03 22:59:29 -07:00
|
|
|
ALfloat (*mixmtx)[sNumBands][MAX_AMBI_CHANNELS]{mMatrix.Dual};
|
|
|
|
ALuint enabled{mEnabled};
|
|
|
|
for(FloatBufferLine &outbuf : OutBuffer)
|
2016-03-15 05:08:05 -07:00
|
|
|
{
|
2019-07-03 22:59:29 -07:00
|
|
|
if(LIKELY(enabled&1))
|
|
|
|
{
|
|
|
|
MixRowSamples(outbuf, (*mixmtx)[sHFBand], hfsamples, 0, SamplesToDo);
|
|
|
|
MixRowSamples(outbuf, (*mixmtx)[sLFBand], lfsamples, 0, SamplesToDo);
|
|
|
|
}
|
|
|
|
++mixmtx;
|
|
|
|
enabled >>= 1;
|
2016-03-15 05:08:05 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2019-06-05 19:26:54 -07:00
|
|
|
const al::span<const FloatBufferLine> insamples{InSamples, mNumChannels};
|
2019-07-03 22:59:29 -07:00
|
|
|
ALfloat (*mixmtx)[MAX_AMBI_CHANNELS]{mMatrix.Single};
|
|
|
|
ALuint enabled{mEnabled};
|
|
|
|
for(FloatBufferLine &outbuf : OutBuffer)
|
2016-03-26 17:33:49 -07:00
|
|
|
{
|
2019-07-03 22:59:29 -07:00
|
|
|
if(LIKELY(enabled&1))
|
|
|
|
MixRowSamples(outbuf, *mixmtx, insamples, 0, SamplesToDo);
|
|
|
|
++mixmtx;
|
|
|
|
enabled >>= 1;
|
2016-03-26 17:33:49 -07:00
|
|
|
}
|
2016-03-15 05:08:05 -07:00
|
|
|
}
|
|
|
|
}
|
2016-03-23 12:53:36 -07:00
|
|
|
|
2016-07-30 09:29:21 -07:00
|
|
|
|
2019-02-22 22:35:37 -08:00
|
|
|
std::array<ALfloat,MAX_AMBI_ORDER+1> BFormatDec::GetHFOrderScales(const ALsizei in_order, const ALsizei out_order) noexcept
|
2019-01-06 17:45:44 -08:00
|
|
|
{
|
|
|
|
std::array<ALfloat,MAX_AMBI_ORDER+1> ret{};
|
|
|
|
|
|
|
|
assert(out_order >= in_order);
|
|
|
|
ASSUME(out_order >= in_order);
|
|
|
|
|
|
|
|
const ALfloat (&target)[MAX_AMBI_ORDER+1] = GetDecoderHFScales(out_order);
|
|
|
|
const ALfloat (&input)[MAX_AMBI_ORDER+1] = GetDecoderHFScales(in_order);
|
|
|
|
|
|
|
|
for(ALsizei i{0};i < in_order+1;++i)
|
|
|
|
ret[i] = input[i] / target[i];
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|