aboutsummaryrefslogtreecommitdiffstats
path: root/Alc
diff options
context:
space:
mode:
authorChris Robinson <[email protected]>2016-03-23 12:53:36 -0700
committerChris Robinson <[email protected]>2016-03-23 15:10:59 -0700
commit147274f165b5cf8f1f004567c777e0e274c9e228 (patch)
tree4cfa2bff040a95b6847604f010602425b259ae9c /Alc
parent0dc35784dbaa37857e988582f41482ef9b59d8a0 (diff)
Up-sample first-order content when using a higher order HQ decoder
Diffstat (limited to 'Alc')
-rw-r--r--Alc/ALu.c8
-rw-r--r--Alc/bformatdec.c88
-rw-r--r--Alc/bformatdec.h5
-rw-r--r--Alc/panning.c2
4 files changed, 101 insertions, 2 deletions
diff --git a/Alc/ALu.c b/Alc/ALu.c
index b5b7de9c..206aceda 100644
--- a/Alc/ALu.c
+++ b/Alc/ALu.c
@@ -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
diff --git a/Alc/bformatdec.c b/Alc/bformatdec.c
index 37be67e4..ab148d1b 100644
--- a/Alc/bformatdec.c
+++ b/Alc/bformatdec.c
@@ -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;
+ }
+ }
+}
diff --git a/Alc/bformatdec.h b/Alc/bformatdec.h
index 5f17d711..623e7b09 100644
--- a/Alc/bformatdec.h
+++ b/Alc/bformatdec.h
@@ -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 */
diff --git a/Alc/panning.c b/Alc/panning.c
index 031b518d..9c504b04 100644
--- a/Alc/panning.c
+++ b/Alc/panning.c
@@ -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;