Up-sample first-order content when using a higher order HQ decoder

This commit is contained in:
Chris Robinson 2016-03-23 12:53:36 -07:00
parent 0dc35784db
commit 147274f165
4 changed files with 101 additions and 2 deletions

View File

@ -1367,6 +1367,9 @@ ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size)
memset(device->VirtOut.Buffer[c], 0, SamplesToDo*sizeof(ALfloat));
for(c = 0;c < device->RealOut.NumChannels;c++)
memset(device->RealOut.Buffer[c], 0, SamplesToDo*sizeof(ALfloat));
if(device->Dry.Buffer != device->FOAOut.Buffer)
for(c = 0;c < device->FOAOut.NumChannels;c++)
memset(device->FOAOut.Buffer[c], 0, SamplesToDo*sizeof(ALfloat));
V0(device->Backend,lock)();
@ -1467,6 +1470,11 @@ ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size)
}
else if(device->AmbiDecoder)
{
if(device->VirtOut.Buffer != device->FOAOut.Buffer)
bformatdec_upSample(device->AmbiDecoder,
device->VirtOut.Buffer, device->FOAOut.Buffer,
device->FOAOut.NumChannels, SamplesToDo
);
bformatdec_process(device->AmbiDecoder,
device->RealOut.Buffer, device->RealOut.NumChannels,
device->VirtOut.Buffer, SamplesToDo

View File

@ -5,6 +5,8 @@
#include "ambdec.h"
#include "alu.h"
#include "threads.h"
typedef struct BandSplitter {
ALfloat coeff;
@ -105,6 +107,46 @@ static const ALfloat FuMa2N3DScale[MAX_AMBI_COEFFS] = {
};
static const ALfloat SquareMatrixHF[4][MAX_AMBI_COEFFS] = {
{ 0.353553f, 0.204094f, 0.0f, 0.204094f },
{ 0.353553f, -0.204094f, 0.0f, 0.204094f },
{ 0.353553f, 0.204094f, 0.0f, -0.204094f },
{ 0.353553f, -0.204094f, 0.0f, -0.204094f },
};
static ALfloat SquareEncoder[4][MAX_AMBI_COEFFS];
static const ALfloat CubeMatrixHF[8][MAX_AMBI_COEFFS] = {
{ 0.25f, 0.14425f, 0.14425f, 0.14425f },
{ 0.25f, -0.14425f, 0.14425f, 0.14425f },
{ 0.25f, 0.14425f, 0.14425f, -0.14425f },
{ 0.25f, -0.14425f, 0.14425f, -0.14425f },
{ 0.25f, 0.14425f, -0.14425f, 0.14425f },
{ 0.25f, -0.14425f, -0.14425f, 0.14425f },
{ 0.25f, 0.14425f, -0.14425f, -0.14425f },
{ 0.25f, -0.14425f, -0.14425f, -0.14425f },
};
static ALfloat CubeEncoder[8][MAX_AMBI_COEFFS];
static alonce_flag encoder_inited = AL_ONCE_FLAG_INIT;
static void init_encoder(void)
{
CalcXYZCoeffs(-0.577350269f, 0.577350269f, -0.577350269f, CubeEncoder[0]);
CalcXYZCoeffs( 0.577350269f, 0.577350269f, -0.577350269f, CubeEncoder[1]);
CalcXYZCoeffs(-0.577350269f, 0.577350269f, 0.577350269f, CubeEncoder[2]);
CalcXYZCoeffs( 0.577350269f, 0.577350269f, 0.577350269f, CubeEncoder[3]);
CalcXYZCoeffs(-0.577350269f, -0.577350269f, -0.577350269f, CubeEncoder[4]);
CalcXYZCoeffs( 0.577350269f, -0.577350269f, -0.577350269f, CubeEncoder[5]);
CalcXYZCoeffs(-0.577350269f, -0.577350269f, 0.577350269f, CubeEncoder[6]);
CalcXYZCoeffs( 0.577350269f, -0.577350269f, 0.577350269f, CubeEncoder[7]);
CalcXYZCoeffs(-0.707106781f, 0.0f, -0.707106781f, SquareEncoder[0]);
CalcXYZCoeffs( 0.707106781f, 0.0f, -0.707106781f, SquareEncoder[1]);
CalcXYZCoeffs(-0.707106781f, 0.0f, 0.707106781f, SquareEncoder[2]);
CalcXYZCoeffs( 0.707106781f, 0.0f, 0.707106781f, SquareEncoder[3]);
}
/* NOTE: Low-frequency (LF) fields and BandSplitter filters are unused with
* single-band decoding
*/
@ -119,12 +161,19 @@ typedef struct BFormatDec {
ALfloat (*SamplesHF)[BUFFERSIZE];
ALfloat (*SamplesLF)[BUFFERSIZE];
struct {
const ALfloat (*restrict MatrixHF)[MAX_AMBI_COEFFS];
const ALfloat (*restrict Encoder)[MAX_AMBI_COEFFS];
ALuint NumChannels;
} UpSampler;
ALuint NumChannels;
ALboolean DualBand;
} BFormatDec;
BFormatDec *bformatdec_alloc()
{
alcall_once(&encoder_inited, init_encoder);
return al_calloc(16, sizeof(BFormatDec));
}
@ -172,6 +221,19 @@ void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALuint chancount,
else if(conf->CoeffScale == ADS_FuMa)
coeff_scale = FuMa2N3DScale;
if((conf->ChanMask & ~0x831b))
{
dec->UpSampler.MatrixHF = CubeMatrixHF;
dec->UpSampler.Encoder = (const ALfloat(*)[MAX_AMBI_COEFFS])CubeEncoder;
dec->UpSampler.NumChannels = 8;
}
else
{
dec->UpSampler.MatrixHF = SquareMatrixHF;
dec->UpSampler.Encoder = (const ALfloat(*)[MAX_AMBI_COEFFS])SquareEncoder;
dec->UpSampler.NumChannels = 4;
}
if(conf->FreqBands == 1)
{
dec->DualBand = AL_FALSE;
@ -264,3 +326,29 @@ void bformatdec_process(struct BFormatDec *dec, ALfloat (*restrict OutBuffer)[BU
dec->NumChannels, SamplesToDo);
}
}
void bformatdec_upSample(struct BFormatDec *dec, ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALfloat (*restrict InSamples)[BUFFERSIZE], ALuint InChannels, ALuint SamplesToDo)
{
ALuint i, j, k;
/* This up-sampler is very simplistic. It essentially decodes the first-
* order content to a square channel array (or cube if height is desired),
* then encodes those points onto the higher order soundfield.
*/
for(k = 0;k < dec->UpSampler.NumChannels;k++)
{
memset(dec->Samples[0], 0, SamplesToDo*sizeof(ALfloat));
apply_row(dec->Samples[0], dec->UpSampler.MatrixHF[k], InSamples,
InChannels, SamplesToDo);
for(j = 0;j < dec->NumChannels;j++)
{
ALfloat gain = dec->UpSampler.Encoder[k][j];
if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD))
continue;
for(i = 0;i < SamplesToDo;i++)
OutBuffer[j][i] += dec->Samples[0][i] * gain;
}
}
}

View File

@ -10,6 +10,11 @@ struct BFormatDec *bformatdec_alloc();
void bformatdec_free(struct BFormatDec *dec);
int bformatdec_getOrder(const struct BFormatDec *dec);
void bformatdec_reset(struct BFormatDec *dec, const struct AmbDecConf *conf, ALuint chancount, ALuint srate, const ALuint chanmap[MAX_OUTPUT_CHANNELS]);
/* Decodes the ambisonic input to the given output channels. */
void bformatdec_process(struct BFormatDec *dec, ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALuint OutChannels, ALfloat (*restrict InSamples)[BUFFERSIZE], ALuint SamplesToDo);
/* Up-samples a first-order input to the decoder's configuration. */
void bformatdec_upSample(struct BFormatDec *dec, ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALfloat (*restrict InSamples)[BUFFERSIZE], ALuint InChannels, ALuint SamplesToDo);
#endif /* BFORMATDEC_H */

View File

@ -641,8 +641,6 @@ ALvoid aluInitPanning(ALCdevice *device)
if(!MakeSpeakerMap(device, &conf, speakermap))
goto ambi_fail;
if(conf.ChanMask > 0xf)
ERR("Second-order HQ decoding does not currently handle first-order sources\n");
count = (conf.ChanMask > 0xf) ? COUNTOF(Ambi3D) : 4;
chanmap = Ambi3D;
ambiscale = 1.0f;