2016-03-15 05:08:05 -07:00
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
|
2018-12-08 04:10:45 -08:00
|
|
|
#include <cmath>
|
2018-11-03 18:00:05 -07:00
|
|
|
#include <array>
|
|
|
|
#include <vector>
|
2018-12-08 01:32:43 -08:00
|
|
|
#include <numeric>
|
2018-12-08 04:10:45 -08:00
|
|
|
#include <algorithm>
|
2018-12-08 01:32:43 -08:00
|
|
|
#include <functional>
|
2018-11-03 18:00:05 -07:00
|
|
|
|
2016-03-15 05:08:05 -07:00
|
|
|
#include "bformatdec.h"
|
|
|
|
#include "ambdec.h"
|
2018-04-21 23:23:46 -07:00
|
|
|
#include "filters/splitter.h"
|
2016-03-15 05:08:05 -07:00
|
|
|
#include "alu.h"
|
|
|
|
|
2016-03-23 12:53:36 -07:00
|
|
|
#include "threads.h"
|
2016-03-29 00:44:58 -07:00
|
|
|
#include "almalloc.h"
|
2016-03-23 12:53:36 -07:00
|
|
|
|
2016-03-15 05:08:05 -07:00
|
|
|
|
2018-02-13 13:47:35 -08:00
|
|
|
/* NOTE: These are scale factors as applied to Ambisonics content. Decoder
|
|
|
|
* coefficients should be divided by these values to get proper N3D scalings.
|
|
|
|
*/
|
|
|
|
const ALfloat N3D2N3DScale[MAX_AMBI_COEFFS] = {
|
2016-03-15 05:08:05 -07:00
|
|
|
1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f,
|
|
|
|
1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f
|
|
|
|
};
|
2018-02-13 13:47:35 -08:00
|
|
|
const ALfloat SN3D2N3DScale[MAX_AMBI_COEFFS] = {
|
2016-03-15 05:08:05 -07:00
|
|
|
1.000000000f, /* ACN 0 (W), sqrt(1) */
|
|
|
|
1.732050808f, /* ACN 1 (Y), sqrt(3) */
|
|
|
|
1.732050808f, /* ACN 2 (Z), sqrt(3) */
|
|
|
|
1.732050808f, /* ACN 3 (X), sqrt(3) */
|
|
|
|
2.236067978f, /* ACN 4 (V), sqrt(5) */
|
|
|
|
2.236067978f, /* ACN 5 (T), sqrt(5) */
|
|
|
|
2.236067978f, /* ACN 6 (R), sqrt(5) */
|
|
|
|
2.236067978f, /* ACN 7 (S), sqrt(5) */
|
|
|
|
2.236067978f, /* ACN 8 (U), sqrt(5) */
|
|
|
|
2.645751311f, /* ACN 9 (Q), sqrt(7) */
|
|
|
|
2.645751311f, /* ACN 10 (O), sqrt(7) */
|
|
|
|
2.645751311f, /* ACN 11 (M), sqrt(7) */
|
|
|
|
2.645751311f, /* ACN 12 (K), sqrt(7) */
|
|
|
|
2.645751311f, /* ACN 13 (L), sqrt(7) */
|
|
|
|
2.645751311f, /* ACN 14 (N), sqrt(7) */
|
|
|
|
2.645751311f, /* ACN 15 (P), sqrt(7) */
|
|
|
|
};
|
2018-02-13 13:47:35 -08:00
|
|
|
const ALfloat FuMa2N3DScale[MAX_AMBI_COEFFS] = {
|
2016-03-15 05:08:05 -07:00
|
|
|
1.414213562f, /* ACN 0 (W), sqrt(2) */
|
|
|
|
1.732050808f, /* ACN 1 (Y), sqrt(3) */
|
|
|
|
1.732050808f, /* ACN 2 (Z), sqrt(3) */
|
|
|
|
1.732050808f, /* ACN 3 (X), sqrt(3) */
|
|
|
|
1.936491673f, /* ACN 4 (V), sqrt(15)/2 */
|
|
|
|
1.936491673f, /* ACN 5 (T), sqrt(15)/2 */
|
|
|
|
2.236067978f, /* ACN 6 (R), sqrt(5) */
|
|
|
|
1.936491673f, /* ACN 7 (S), sqrt(15)/2 */
|
|
|
|
1.936491673f, /* ACN 8 (U), sqrt(15)/2 */
|
|
|
|
2.091650066f, /* ACN 9 (Q), sqrt(35/8) */
|
|
|
|
1.972026594f, /* ACN 10 (O), sqrt(35)/3 */
|
|
|
|
2.231093404f, /* ACN 11 (M), sqrt(224/45) */
|
|
|
|
2.645751311f, /* ACN 12 (K), sqrt(7) */
|
|
|
|
2.231093404f, /* ACN 13 (L), sqrt(224/45) */
|
|
|
|
1.972026594f, /* ACN 14 (N), sqrt(35)/3 */
|
|
|
|
2.091650066f, /* ACN 15 (P), sqrt(35/8) */
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2018-11-03 18:00:05 -07:00
|
|
|
namespace {
|
|
|
|
|
2018-02-12 20:58:39 -08:00
|
|
|
#define HF_BAND 0
|
|
|
|
#define LF_BAND 1
|
2018-12-08 02:50:34 -08:00
|
|
|
static_assert(BFormatDec::sNumBands == 2, "Unexpected BFormatDec::sNumBands");
|
|
|
|
static_assert(AmbiUpsampler::sNumBands == 2, "Unexpected AmbiUpsampler::sNumBands");
|
2016-07-17 00:29:02 -07:00
|
|
|
|
2016-09-06 03:10:38 -07:00
|
|
|
/* These points are in AL coordinates! */
|
2018-11-04 15:19:48 -08:00
|
|
|
constexpr ALfloat Ambi3DPoints[8][3] = {
|
2016-07-30 09:29:21 -07:00
|
|
|
{ -0.577350269f, 0.577350269f, -0.577350269f },
|
|
|
|
{ 0.577350269f, 0.577350269f, -0.577350269f },
|
|
|
|
{ -0.577350269f, 0.577350269f, 0.577350269f },
|
|
|
|
{ 0.577350269f, 0.577350269f, 0.577350269f },
|
|
|
|
{ -0.577350269f, -0.577350269f, -0.577350269f },
|
|
|
|
{ 0.577350269f, -0.577350269f, -0.577350269f },
|
|
|
|
{ -0.577350269f, -0.577350269f, 0.577350269f },
|
|
|
|
{ 0.577350269f, -0.577350269f, 0.577350269f },
|
|
|
|
};
|
2018-11-04 15:19:48 -08:00
|
|
|
constexpr ALfloat Ambi3DDecoder[8][MAX_AMBI_COEFFS] = {
|
2018-02-12 21:24:58 -08:00
|
|
|
{ 0.125f, 0.125f, 0.125f, 0.125f },
|
|
|
|
{ 0.125f, -0.125f, 0.125f, 0.125f },
|
|
|
|
{ 0.125f, 0.125f, 0.125f, -0.125f },
|
|
|
|
{ 0.125f, -0.125f, 0.125f, -0.125f },
|
|
|
|
{ 0.125f, 0.125f, -0.125f, 0.125f },
|
|
|
|
{ 0.125f, -0.125f, -0.125f, 0.125f },
|
|
|
|
{ 0.125f, 0.125f, -0.125f, -0.125f },
|
|
|
|
{ 0.125f, -0.125f, -0.125f, -0.125f },
|
|
|
|
};
|
2018-11-04 15:19:48 -08:00
|
|
|
constexpr ALfloat Ambi3DDecoderHFScale[MAX_AMBI_COEFFS] = {
|
2018-02-12 21:24:58 -08:00
|
|
|
2.0f,
|
|
|
|
1.15470054f, 1.15470054f, 1.15470054f
|
2016-04-09 08:04:56 -07:00
|
|
|
};
|
2016-03-23 12:53:36 -07:00
|
|
|
|
|
|
|
|
2018-11-03 18:00:05 -07:00
|
|
|
#define INVALID_UPSAMPLE_INDEX INT_MAX
|
|
|
|
ALsizei GetACNIndex(const BFChannelConfig *chans, ALsizei numchans, ALsizei acn)
|
|
|
|
{
|
|
|
|
ALsizei i;
|
|
|
|
for(i = 0;i < numchans;i++)
|
|
|
|
{
|
|
|
|
if(chans[i].Index == acn)
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
return INVALID_UPSAMPLE_INDEX;
|
|
|
|
}
|
|
|
|
#define GetChannelForACN(b, a) GetACNIndex((b).Ambi.Map, (b).NumChannels, (a))
|
|
|
|
|
|
|
|
} // namespace
|
|
|
|
|
|
|
|
|
2018-12-08 02:50:34 -08:00
|
|
|
void BFormatDec::reset(const AmbDecConf *conf, ALsizei chancount, ALuint srate, const ALsizei (&chanmap)[MAX_OUTPUT_CHANNELS])
|
2016-03-15 05:08:05 -07:00
|
|
|
{
|
2018-11-04 15:19:48 -08:00
|
|
|
static constexpr ALsizei map2DTo3D[MAX_AMBI2D_COEFFS] = {
|
2016-03-25 19:57:25 -07:00
|
|
|
0, 1, 3, 4, 8, 9, 15
|
|
|
|
};
|
2018-02-13 13:47:35 -08:00
|
|
|
const ALfloat *coeff_scale = N3D2N3DScale;
|
2016-03-15 05:08:05 -07:00
|
|
|
|
2018-12-08 02:50:34 -08:00
|
|
|
mSamples.clear();
|
|
|
|
mSamplesHF = nullptr;
|
|
|
|
mSamplesLF = nullptr;
|
2016-03-15 05:08:05 -07:00
|
|
|
|
2018-12-08 02:50:34 -08:00
|
|
|
mNumChannels = chancount;
|
|
|
|
mSamples.resize(mNumChannels * 2);
|
|
|
|
mSamplesHF = mSamples.data();
|
|
|
|
mSamplesLF = mSamplesHF + mNumChannels;
|
2016-03-15 05:08:05 -07:00
|
|
|
|
2018-12-08 02:50:34 -08:00
|
|
|
mEnabled = std::accumulate(std::begin(chanmap), std::begin(chanmap)+conf->NumSpeakers, 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
|
|
|
|
2018-11-03 19:51:23 -07:00
|
|
|
if(conf->CoeffScale == AmbDecScale::SN3D)
|
2016-03-15 05:08:05 -07:00
|
|
|
coeff_scale = SN3D2N3DScale;
|
2018-11-03 19:51:23 -07:00
|
|
|
else if(conf->CoeffScale == AmbDecScale::FuMa)
|
2016-03-15 05:08:05 -07:00
|
|
|
coeff_scale = FuMa2N3DScale;
|
|
|
|
|
2018-12-08 04:10:45 -08:00
|
|
|
mUpSampler[0].XOver.init(400.0f / (float)srate);
|
|
|
|
std::fill(std::begin(mUpSampler[0].Gains), std::end(mUpSampler[0].Gains), 0.0f);
|
|
|
|
std::fill(std::begin(mUpSampler)+1, std::end(mUpSampler), mUpSampler[0]);
|
2017-01-24 19:03:51 -08:00
|
|
|
|
2018-12-08 01:32:43 -08:00
|
|
|
const bool periphonic{(conf->ChanMask&AMBI_PERIPHONIC_MASK) != 0};
|
|
|
|
if(periphonic)
|
|
|
|
{
|
2018-12-08 02:50:34 -08:00
|
|
|
mUpSampler[0].Gains[HF_BAND] = (conf->ChanMask > 0x1ff) ? W_SCALE_3H3P :
|
|
|
|
(conf->ChanMask > 0xf) ? W_SCALE_2H2P : 1.0f;
|
|
|
|
mUpSampler[0].Gains[LF_BAND] = 1.0f;
|
2018-12-08 01:32:43 -08:00
|
|
|
for(ALsizei i{1};i < 4;i++)
|
2017-01-24 19:03:51 -08:00
|
|
|
{
|
2018-12-08 02:50:34 -08:00
|
|
|
mUpSampler[i].Gains[HF_BAND] = (conf->ChanMask > 0x1ff) ? XYZ_SCALE_3H3P :
|
|
|
|
(conf->ChanMask > 0xf) ? XYZ_SCALE_2H2P : 1.0f;
|
|
|
|
mUpSampler[i].Gains[LF_BAND] = 1.0f;
|
2017-01-24 19:03:51 -08:00
|
|
|
}
|
2016-03-23 12:53:36 -07:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2018-12-08 02:50:34 -08:00
|
|
|
mUpSampler[0].Gains[HF_BAND] = (conf->ChanMask > 0x1ff) ? W_SCALE_3H0P :
|
|
|
|
(conf->ChanMask > 0xf) ? W_SCALE_2H0P : 1.0f;
|
|
|
|
mUpSampler[0].Gains[LF_BAND] = 1.0f;
|
2018-12-08 01:32:43 -08:00
|
|
|
for(ALsizei i{1};i < 3;i++)
|
2017-01-24 19:03:51 -08:00
|
|
|
{
|
2018-12-08 02:50:34 -08:00
|
|
|
mUpSampler[i].Gains[HF_BAND] = (conf->ChanMask > 0x1ff) ? XYZ_SCALE_3H0P :
|
|
|
|
(conf->ChanMask > 0xf) ? XYZ_SCALE_2H0P : 1.0f;
|
|
|
|
mUpSampler[i].Gains[LF_BAND] = 1.0f;
|
2017-01-24 19:03:51 -08:00
|
|
|
}
|
2018-12-08 02:50:34 -08:00
|
|
|
mUpSampler[3].Gains[HF_BAND] = 0.0f;
|
|
|
|
mUpSampler[3].Gains[LF_BAND] = 0.0f;
|
2016-03-23 12:53:36 -07:00
|
|
|
}
|
|
|
|
|
2018-12-08 14:22:20 -08:00
|
|
|
mMatrix = MatrixU{};
|
2016-03-15 05:08:05 -07:00
|
|
|
if(conf->FreqBands == 1)
|
|
|
|
{
|
2018-12-08 02:50:34 -08:00
|
|
|
mDualBand = AL_FALSE;
|
2018-12-08 01:32:43 -08:00
|
|
|
for(ALsizei i{0};i < conf->NumSpeakers;i++)
|
2016-07-17 00:29:02 -07:00
|
|
|
{
|
2017-01-29 16:42:02 -08:00
|
|
|
ALsizei chan = chanmap[i];
|
2016-07-17 00:29:02 -07:00
|
|
|
ALfloat gain;
|
2017-01-29 16:42:02 -08:00
|
|
|
ALsizei j, k;
|
2016-07-17 00:29:02 -07:00
|
|
|
|
2017-02-28 19:44:34 -08:00
|
|
|
if(!periphonic)
|
2016-07-17 00:29:02 -07:00
|
|
|
{
|
2016-07-17 00:46:18 -07:00
|
|
|
for(j = 0,k = 0;j < MAX_AMBI2D_COEFFS;j++)
|
2016-07-17 00:29:02 -07:00
|
|
|
{
|
2017-01-29 16:42:02 -08:00
|
|
|
ALsizei l = map2DTo3D[j];
|
2016-07-17 00:29:02 -07:00
|
|
|
if(j == 0) gain = conf->HFOrderGain[0];
|
|
|
|
else if(j == 1) gain = conf->HFOrderGain[1];
|
|
|
|
else if(j == 3) gain = conf->HFOrderGain[2];
|
|
|
|
else if(j == 5) gain = conf->HFOrderGain[3];
|
|
|
|
if((conf->ChanMask&(1<<l)))
|
2018-12-08 02:50:34 -08:00
|
|
|
mMatrix.Single[chan][j] = conf->HFMatrix[i][k++] / coeff_scale[l] * gain;
|
2016-07-17 00:29:02 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
for(j = 0,k = 0;j < MAX_AMBI_COEFFS;j++)
|
|
|
|
{
|
|
|
|
if(j == 0) gain = conf->HFOrderGain[0];
|
|
|
|
else if(j == 1) gain = conf->HFOrderGain[1];
|
|
|
|
else if(j == 4) gain = conf->HFOrderGain[2];
|
|
|
|
else if(j == 9) gain = conf->HFOrderGain[3];
|
|
|
|
if((conf->ChanMask&(1<<j)))
|
2018-12-08 02:50:34 -08:00
|
|
|
mMatrix.Single[chan][j] = conf->HFMatrix[i][k++] / coeff_scale[j] * gain;
|
2016-07-17 00:29:02 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-03-15 05:08:05 -07:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2018-12-08 02:50:34 -08:00
|
|
|
mDualBand = AL_TRUE;
|
2016-03-15 05:08:05 -07:00
|
|
|
|
2018-12-08 04:10:45 -08:00
|
|
|
mXOver[0].init(conf->XOverFreq / (float)srate);
|
|
|
|
std::fill(std::begin(mXOver)+1, std::end(mXOver), mXOver[0]);
|
2016-03-15 05:08:05 -07:00
|
|
|
|
2018-12-08 04:10:45 -08:00
|
|
|
float ratio{std::pow(10.0f, conf->XOverRatio / 40.0f)};
|
2018-12-08 01:32:43 -08:00
|
|
|
for(ALsizei i{0};i < conf->NumSpeakers;i++)
|
2016-03-15 05:08:05 -07:00
|
|
|
{
|
2017-01-29 16:42:02 -08:00
|
|
|
ALsizei chan = chanmap[i];
|
2016-03-15 05:08:05 -07:00
|
|
|
|
2018-12-08 04:10:45 -08:00
|
|
|
ALfloat gain{};
|
2017-02-28 19:44:34 -08:00
|
|
|
if(!periphonic)
|
2016-03-15 05:08:05 -07:00
|
|
|
{
|
2018-12-08 04:10:45 -08:00
|
|
|
for(ALsizei j{0},k{0};j < MAX_AMBI2D_COEFFS;j++)
|
2016-07-17 00:29:02 -07:00
|
|
|
{
|
2017-01-29 16:42:02 -08:00
|
|
|
ALsizei l = map2DTo3D[j];
|
2016-07-17 00:29:02 -07:00
|
|
|
if(j == 0) gain = conf->HFOrderGain[0] * ratio;
|
|
|
|
else if(j == 1) gain = conf->HFOrderGain[1] * ratio;
|
|
|
|
else if(j == 3) gain = conf->HFOrderGain[2] * ratio;
|
|
|
|
else if(j == 5) gain = conf->HFOrderGain[3] * ratio;
|
|
|
|
if((conf->ChanMask&(1<<l)))
|
2018-12-08 02:50:34 -08:00
|
|
|
mMatrix.Dual[chan][HF_BAND][j] = conf->HFMatrix[i][k++] / coeff_scale[l] *
|
|
|
|
gain;
|
2016-07-17 00:29:02 -07:00
|
|
|
}
|
2018-12-08 04:10:45 -08:00
|
|
|
for(ALsizei j{0},k{0};j < MAX_AMBI2D_COEFFS;j++)
|
2016-03-25 19:57:25 -07:00
|
|
|
{
|
2017-01-29 16:42:02 -08:00
|
|
|
ALsizei l = map2DTo3D[j];
|
2016-03-25 19:57:25 -07:00
|
|
|
if(j == 0) gain = conf->LFOrderGain[0] / ratio;
|
|
|
|
else if(j == 1) gain = conf->LFOrderGain[1] / ratio;
|
|
|
|
else if(j == 3) gain = conf->LFOrderGain[2] / ratio;
|
|
|
|
else if(j == 5) gain = conf->LFOrderGain[3] / ratio;
|
|
|
|
if((conf->ChanMask&(1<<l)))
|
2018-12-08 02:50:34 -08:00
|
|
|
mMatrix.Dual[chan][LF_BAND][j] = conf->LFMatrix[i][k++] / coeff_scale[l] *
|
|
|
|
gain;
|
2016-03-25 19:57:25 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2018-12-08 04:10:45 -08:00
|
|
|
for(ALsizei j{0},k{0};j < MAX_AMBI_COEFFS;j++)
|
2016-07-17 00:29:02 -07:00
|
|
|
{
|
|
|
|
if(j == 0) gain = conf->HFOrderGain[0] * ratio;
|
|
|
|
else if(j == 1) gain = conf->HFOrderGain[1] * ratio;
|
|
|
|
else if(j == 4) gain = conf->HFOrderGain[2] * ratio;
|
|
|
|
else if(j == 9) gain = conf->HFOrderGain[3] * ratio;
|
|
|
|
if((conf->ChanMask&(1<<j)))
|
2018-12-08 02:50:34 -08:00
|
|
|
mMatrix.Dual[chan][HF_BAND][j] = conf->HFMatrix[i][k++] / coeff_scale[j] *
|
|
|
|
gain;
|
2016-07-17 00:29:02 -07:00
|
|
|
}
|
2018-12-08 04:10:45 -08:00
|
|
|
for(ALsizei j{0},k{0};j < MAX_AMBI_COEFFS;j++)
|
2016-03-25 19:57:25 -07:00
|
|
|
{
|
|
|
|
if(j == 0) gain = conf->LFOrderGain[0] / ratio;
|
|
|
|
else if(j == 1) gain = conf->LFOrderGain[1] / ratio;
|
|
|
|
else if(j == 4) gain = conf->LFOrderGain[2] / ratio;
|
|
|
|
else if(j == 9) gain = conf->LFOrderGain[3] / ratio;
|
|
|
|
if((conf->ChanMask&(1<<j)))
|
2018-12-08 02:50:34 -08:00
|
|
|
mMatrix.Dual[chan][LF_BAND][j] = conf->LFMatrix[i][k++] / coeff_scale[j] *
|
|
|
|
gain;
|
2016-03-25 19:57:25 -07:00
|
|
|
}
|
2016-03-15 05:08:05 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-12-08 02:50:34 -08:00
|
|
|
void BFormatDec::process(ALfloat (*RESTRICT OutBuffer)[BUFFERSIZE], const ALsizei OutChannels, const ALfloat (*RESTRICT InSamples)[BUFFERSIZE], const ALsizei SamplesToDo)
|
2016-03-15 05:08:05 -07:00
|
|
|
{
|
2018-12-08 01:32:43 -08:00
|
|
|
ASSUME(OutChannels > 0);
|
|
|
|
ASSUME(SamplesToDo > 0);
|
2016-03-15 05:08:05 -07:00
|
|
|
|
2018-12-08 01:32:43 -08:00
|
|
|
ALsizei chan, i;
|
2018-12-08 02:50:34 -08:00
|
|
|
if(mDualBand)
|
2016-03-15 05:08:05 -07:00
|
|
|
{
|
2018-12-08 02:50:34 -08:00
|
|
|
for(i = 0;i < mNumChannels;i++)
|
|
|
|
mXOver[i].process(mSamplesHF[i].data(), mSamplesLF[i].data(), InSamples[i],
|
|
|
|
SamplesToDo);
|
2016-03-15 05:08:05 -07:00
|
|
|
|
|
|
|
for(chan = 0;chan < OutChannels;chan++)
|
|
|
|
{
|
2018-12-08 02:50:34 -08:00
|
|
|
if(UNLIKELY(!(mEnabled&(1<<chan))))
|
2016-03-28 14:50:18 -07:00
|
|
|
continue;
|
|
|
|
|
2018-12-08 02:50:34 -08:00
|
|
|
std::fill(std::begin(mChannelMix), std::begin(mChannelMix)+SamplesToDo, 0.0f);
|
|
|
|
MixRowSamples(mChannelMix, mMatrix.Dual[chan][HF_BAND],
|
|
|
|
&reinterpret_cast<ALfloat(&)[BUFFERSIZE]>(mSamplesHF[0]),
|
|
|
|
mNumChannels, 0, SamplesToDo
|
2016-07-17 00:29:02 -07:00
|
|
|
);
|
2018-12-08 02:50:34 -08:00
|
|
|
MixRowSamples(mChannelMix, mMatrix.Dual[chan][LF_BAND],
|
|
|
|
&reinterpret_cast<ALfloat(&)[BUFFERSIZE]>(mSamplesLF[0]),
|
|
|
|
mNumChannels, 0, SamplesToDo
|
2016-07-17 00:29:02 -07:00
|
|
|
);
|
2016-03-26 17:33:49 -07:00
|
|
|
|
2018-12-08 02:50:34 -08:00
|
|
|
std::transform(std::begin(mChannelMix), std::begin(mChannelMix)+SamplesToDo,
|
2018-12-08 01:32:43 -08:00
|
|
|
OutBuffer[chan], OutBuffer[chan], std::plus<float>());
|
2016-03-15 05:08:05 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
for(chan = 0;chan < OutChannels;chan++)
|
2016-03-26 17:33:49 -07:00
|
|
|
{
|
2018-12-08 02:50:34 -08:00
|
|
|
if(UNLIKELY(!(mEnabled&(1<<chan))))
|
2016-03-28 14:50:18 -07:00
|
|
|
continue;
|
|
|
|
|
2018-12-08 02:50:34 -08:00
|
|
|
std::fill(std::begin(mChannelMix), std::begin(mChannelMix)+SamplesToDo, 0.0f);
|
|
|
|
MixRowSamples(mChannelMix, mMatrix.Single[chan], InSamples,
|
|
|
|
mNumChannels, 0, SamplesToDo);
|
2016-03-26 17:33:49 -07:00
|
|
|
|
2018-12-08 02:50:34 -08:00
|
|
|
std::transform(std::begin(mChannelMix), std::begin(mChannelMix)+SamplesToDo,
|
2018-12-08 01:32:43 -08:00
|
|
|
OutBuffer[chan], OutBuffer[chan], std::plus<float>());
|
2016-03-26 17:33:49 -07:00
|
|
|
}
|
2016-03-15 05:08:05 -07:00
|
|
|
}
|
|
|
|
}
|
2016-03-23 12:53:36 -07:00
|
|
|
|
2018-12-08 02:50:34 -08:00
|
|
|
void BFormatDec::upSample(ALfloat (*RESTRICT OutBuffer)[BUFFERSIZE], const ALfloat (*RESTRICT InSamples)[BUFFERSIZE], const ALsizei InChannels, const ALsizei SamplesToDo)
|
2016-03-23 12:53:36 -07:00
|
|
|
{
|
2018-12-08 01:32:43 -08:00
|
|
|
ASSUME(InChannels > 0);
|
|
|
|
ASSUME(SamplesToDo > 0);
|
2016-04-09 08:04:56 -07:00
|
|
|
|
2017-01-24 19:03:51 -08:00
|
|
|
/* This up-sampler leverages the differences observed in dual-band second-
|
|
|
|
* and third-order decoder matrices compared to first-order. For the same
|
|
|
|
* output channel configuration, the low-frequency matrix has identical
|
|
|
|
* coefficients in the shared input channels, while the high-frequency
|
|
|
|
* matrix has extra scalars applied to the W channel and X/Y/Z channels.
|
|
|
|
* Mixing the first-order content into the higher-order stream with the
|
|
|
|
* appropriate counter-scales applied to the HF response results in the
|
|
|
|
* subsequent higher-order decode generating the same response as a first-
|
|
|
|
* order decode.
|
2016-03-23 12:53:36 -07:00
|
|
|
*/
|
2018-12-08 01:32:43 -08:00
|
|
|
for(ALsizei i{0};i < InChannels;i++)
|
2016-03-23 12:53:36 -07:00
|
|
|
{
|
2016-08-30 04:21:57 -07:00
|
|
|
/* First, split the first-order components into low and high frequency
|
|
|
|
* bands.
|
|
|
|
*/
|
2018-12-08 02:50:34 -08:00
|
|
|
mUpSampler[i].XOver.process(mSamples[HF_BAND].data(), mSamples[LF_BAND].data(),
|
|
|
|
InSamples[i], SamplesToDo);
|
2016-08-30 04:21:57 -07:00
|
|
|
|
|
|
|
/* Now write each band to the output. */
|
2018-12-08 02:50:34 -08:00
|
|
|
MixRowSamples(OutBuffer[i], mUpSampler[i].Gains,
|
|
|
|
&reinterpret_cast<ALfloat(&)[BUFFERSIZE]>(mSamples[0]),
|
|
|
|
sNumBands, 0, SamplesToDo);
|
2016-03-23 12:53:36 -07:00
|
|
|
}
|
|
|
|
}
|
2016-07-30 09:29:21 -07:00
|
|
|
|
|
|
|
|
2018-12-08 02:50:34 -08:00
|
|
|
void AmbiUpsampler::reset(const ALCdevice *device, const ALfloat w_scale, const ALfloat xyz_scale)
|
2016-07-30 09:29:21 -07:00
|
|
|
{
|
2018-12-08 01:32:43 -08:00
|
|
|
using namespace std::placeholders;
|
2016-07-30 09:29:21 -07:00
|
|
|
|
2018-12-08 04:10:45 -08:00
|
|
|
mXOver[0].init(400.0f / (float)device->Frequency);
|
|
|
|
std::fill(std::begin(mXOver)+1, std::end(mXOver), mXOver[0]);
|
2016-07-30 09:29:21 -07:00
|
|
|
|
2018-12-08 14:22:20 -08:00
|
|
|
mGains.fill({});
|
2017-01-24 19:03:51 -08:00
|
|
|
if(device->Dry.CoeffCount > 0)
|
|
|
|
{
|
|
|
|
ALfloat encgains[8][MAX_OUTPUT_CHANNELS];
|
2018-12-08 01:32:43 -08:00
|
|
|
for(size_t k{0u};k < COUNTOF(Ambi3DPoints);k++)
|
2017-01-24 19:03:51 -08:00
|
|
|
{
|
|
|
|
ALfloat coeffs[MAX_AMBI_COEFFS] = { 0.0f };
|
2018-01-11 10:55:35 -08:00
|
|
|
CalcDirectionCoeffs(Ambi3DPoints[k], 0.0f, coeffs);
|
2018-09-19 22:18:46 -07:00
|
|
|
ComputePanGains(&device->Dry, coeffs, 1.0f, encgains[k]);
|
2017-01-24 19:03:51 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* 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.
|
|
|
|
*/
|
2018-12-08 01:32:43 -08:00
|
|
|
for(ALsizei i{0};i < 4;i++)
|
2017-01-24 19:03:51 -08:00
|
|
|
{
|
2018-12-08 01:32:43 -08:00
|
|
|
for(ALsizei j{0};j < device->Dry.NumChannels;j++)
|
2017-01-24 19:03:51 -08:00
|
|
|
{
|
2018-05-18 18:59:27 -07:00
|
|
|
ALdouble gain = 0.0;
|
2018-12-08 01:32:43 -08:00
|
|
|
for(size_t k{0u};k < COUNTOF(Ambi3DDecoder);k++)
|
2018-05-18 18:59:27 -07:00
|
|
|
gain += (ALdouble)Ambi3DDecoder[k][i] * encgains[k][j];
|
2018-12-08 02:50:34 -08:00
|
|
|
mGains[i][j][HF_BAND] = (ALfloat)(gain * Ambi3DDecoderHFScale[i]);
|
|
|
|
mGains[i][j][LF_BAND] = (ALfloat)gain;
|
2017-01-24 19:03:51 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2018-12-08 01:32:43 -08:00
|
|
|
for(ALsizei i{0};i < 4;i++)
|
2017-01-24 19:03:51 -08:00
|
|
|
{
|
|
|
|
ALsizei index = GetChannelForACN(device->Dry, i);
|
|
|
|
if(index != INVALID_UPSAMPLE_INDEX)
|
|
|
|
{
|
|
|
|
ALfloat scale = device->Dry.Ambi.Map[index].Scale;
|
2018-12-08 02:50:34 -08:00
|
|
|
mGains[i][index][HF_BAND] = scale * ((i==0) ? w_scale : xyz_scale);
|
|
|
|
mGains[i][index][LF_BAND] = scale;
|
2017-01-24 19:03:51 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-07-30 09:29:21 -07:00
|
|
|
}
|
|
|
|
|
2018-12-08 02:50:34 -08:00
|
|
|
void AmbiUpsampler::process(ALfloat (*RESTRICT OutBuffer)[BUFFERSIZE], const ALsizei OutChannels, const ALfloat (*RESTRICT InSamples)[BUFFERSIZE], const ALsizei SamplesToDo)
|
2016-07-30 09:29:21 -07:00
|
|
|
{
|
2018-12-08 01:32:43 -08:00
|
|
|
ASSUME(OutChannels > 0);
|
|
|
|
ASSUME(SamplesToDo > 0);
|
2016-07-30 09:29:21 -07:00
|
|
|
|
2018-12-08 01:32:43 -08:00
|
|
|
for(ALsizei i{0};i < 4;i++)
|
2016-07-30 09:29:21 -07:00
|
|
|
{
|
2018-12-08 02:50:34 -08:00
|
|
|
mXOver[i].process(mSamples[HF_BAND], mSamples[LF_BAND], InSamples[i], SamplesToDo);
|
2016-07-30 09:29:21 -07:00
|
|
|
|
2018-12-08 01:32:43 -08:00
|
|
|
for(ALsizei j{0};j < OutChannels;j++)
|
2018-12-08 14:22:20 -08:00
|
|
|
MixRowSamples(OutBuffer[j], mGains[i][j].data(), mSamples, sNumBands, 0, SamplesToDo);
|
2016-07-30 09:29:21 -07:00
|
|
|
}
|
|
|
|
}
|