aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChris Robinson <[email protected]>2017-02-19 22:47:59 -0800
committerChris Robinson <[email protected]>2017-02-19 22:47:59 -0800
commit3761336e6cf49a7cd5075424b3c8c4a1f5e5b226 (patch)
tree109b4c30187680c8216186445b728c1592fad823
parent9da152a9c8b9f3a6f019c77e0324772344fc9156 (diff)
Apply distance compensation when writing to the output
-rw-r--r--Alc/ALu.c51
-rw-r--r--Alc/bformatdec.c115
-rw-r--r--Alc/bformatdec.h2
-rw-r--r--Alc/panning.c48
-rw-r--r--OpenAL32/Include/alMain.h12
5 files changed, 106 insertions, 122 deletions
diff --git a/Alc/ALu.c b/Alc/ALu.c
index 2476622b..1fca0ed0 100644
--- a/Alc/ALu.c
+++ b/Alc/ALu.c
@@ -1373,15 +1373,39 @@ static inline ALubyte aluF2UB(ALfloat val)
{ return aluF2B(val)+128; }
#define DECL_TEMPLATE(T, func) \
-static void Write_##T(ALfloatBUFFERSIZE *InBuffer, ALvoid *OutBuffer, \
- ALsizei SamplesToDo, ALsizei numchans) \
+static void Write_##T(const ALfloatBUFFERSIZE *InBuffer, ALvoid *OutBuffer, \
+ DistanceComp *distcomp, ALsizei SamplesToDo, \
+ ALsizei numchans) \
{ \
ALsizei i, j; \
for(j = 0;j < numchans;j++) \
{ \
const ALfloat *in = InBuffer[j]; \
T *restrict out = (T*)OutBuffer + j; \
- for(i = 0;i < SamplesToDo;i++) \
+ const ALfloat gain = distcomp[j].Gain; \
+ const ALsizei base = distcomp[j].Length; \
+ if(base > 0 || gain != 1.0f) \
+ { \
+ if(SamplesToDo >= base) \
+ { \
+ for(i = 0;i < base;i++) \
+ out[i*numchans] = func(distcomp[j].Buffer[i]*gain); \
+ for(;i < SamplesToDo;i++) \
+ out[i*numchans] = func(in[i-base]*gain); \
+ memcpy(distcomp[j].Buffer, &in[SamplesToDo-base], \
+ base*sizeof(ALfloat)); \
+ } \
+ else \
+ { \
+ for(i = 0;i < SamplesToDo;i++) \
+ out[i*numchans] = func(distcomp[j].Buffer[i]*gain); \
+ memmove(distcomp[j].Buffer, distcomp[j].Buffer+SamplesToDo, \
+ (base-SamplesToDo)*sizeof(ALfloat)); \
+ memcpy(distcomp[j].Buffer+base-SamplesToDo, in, \
+ SamplesToDo*sizeof(ALfloat)); \
+ } \
+ } \
+ else for(i = 0;i < SamplesToDo;i++) \
out[i*numchans] = func(in[i]); \
} \
}
@@ -1564,33 +1588,34 @@ void aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size)
{
ALfloat (*OutBuffer)[BUFFERSIZE] = device->RealOut.Buffer;
ALsizei OutChannels = device->RealOut.NumChannels;
+ DistanceComp *DistComp = device->ChannelDelay;
-#define WRITE(T, a, b, c, d) do { \
- Write_##T((a), (b), (c), (d)); \
- buffer = (T*)buffer + (c)*(d); \
+#define WRITE(T, a, b, c, d, e) do { \
+ Write_##T(SAFE_CONST(ALfloatBUFFERSIZE*,(a)), (b), (c), (d), (e)); \
+ buffer = (T*)buffer + (d)*(e); \
} while(0)
switch(device->FmtType)
{
case DevFmtByte:
- WRITE(ALbyte, OutBuffer, buffer, SamplesToDo, OutChannels);
+ WRITE(ALbyte, OutBuffer, buffer, DistComp, SamplesToDo, OutChannels);
break;
case DevFmtUByte:
- WRITE(ALubyte, OutBuffer, buffer, SamplesToDo, OutChannels);
+ WRITE(ALubyte, OutBuffer, buffer, DistComp, SamplesToDo, OutChannels);
break;
case DevFmtShort:
- WRITE(ALshort, OutBuffer, buffer, SamplesToDo, OutChannels);
+ WRITE(ALshort, OutBuffer, buffer, DistComp, SamplesToDo, OutChannels);
break;
case DevFmtUShort:
- WRITE(ALushort, OutBuffer, buffer, SamplesToDo, OutChannels);
+ WRITE(ALushort, OutBuffer, buffer, DistComp, SamplesToDo, OutChannels);
break;
case DevFmtInt:
- WRITE(ALint, OutBuffer, buffer, SamplesToDo, OutChannels);
+ WRITE(ALint, OutBuffer, buffer, DistComp, SamplesToDo, OutChannels);
break;
case DevFmtUInt:
- WRITE(ALuint, OutBuffer, buffer, SamplesToDo, OutChannels);
+ WRITE(ALuint, OutBuffer, buffer, DistComp, SamplesToDo, OutChannels);
break;
case DevFmtFloat:
- WRITE(ALfloat, OutBuffer, buffer, SamplesToDo, OutChannels);
+ WRITE(ALfloat, OutBuffer, buffer, DistComp, SamplesToDo, OutChannels);
break;
}
#undef WRITE
diff --git a/Alc/bformatdec.c b/Alc/bformatdec.c
index 549cd42c..5b848ee0 100644
--- a/Alc/bformatdec.c
+++ b/Alc/bformatdec.c
@@ -156,10 +156,6 @@ static void init_bformatdec(void)
}
-#define MAX_DELAY_LENGTH 128
-
-#define INVALID_UPSAMPLE_INDEX INT_MAX
-
/* NOTE: BandSplitter filters are unused with single-band decoding */
typedef struct BFormatDec {
ALboolean Enabled[MAX_OUTPUT_CHANNELS];
@@ -179,11 +175,6 @@ typedef struct BFormatDec {
alignas(16) ALfloat ChannelMix[BUFFERSIZE];
struct {
- alignas(16) ALfloat Buffer[MAX_DELAY_LENGTH];
- ALsizei Length; /* Valid range is [0...MAX_DELAY_LENGTH). */
- } Delay[MAX_OUTPUT_CHANNELS];
-
- struct {
BandSplitter XOver;
ALfloat Gains[FB_Max];
} UpSampler[4];
@@ -235,14 +226,13 @@ int bformatdec_isPeriphonic(const struct BFormatDec *dec)
return dec->Periphonic;
}
-void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALsizei chancount, ALuint srate, const ALsizei chanmap[MAX_OUTPUT_CHANNELS], int flags)
+void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALsizei chancount, ALuint srate, const ALsizei chanmap[MAX_OUTPUT_CHANNELS])
{
static const ALsizei map2DTo3D[MAX_AMBI2D_COEFFS] = {
0, 1, 3, 4, 8, 9, 15
};
const ALfloat *coeff_scale = UnitScale;
- ALfloat distgain[MAX_OUTPUT_CHANNELS];
- ALfloat maxdist, ratio;
+ ALfloat ratio;
ALsizei i;
al_free(dec->Samples);
@@ -300,41 +290,6 @@ void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALsizei chancount
dec->UpSampler[3].Gains[FB_LowFreq] = 0.0f;
}
- maxdist = 0.0f;
- for(i = 0;i < conf->NumSpeakers;i++)
- {
- maxdist = maxf(maxdist, conf->Speakers[i].Distance);
- distgain[i] = 1.0f;
- }
-
- memset(dec->Delay, 0, sizeof(dec->Delay));
- if((flags&BFDF_DistanceComp) && maxdist > 0.0f)
- {
- for(i = 0;i < conf->NumSpeakers;i++)
- {
- ALsizei chan = chanmap[i];
- ALfloat delay;
-
- /* Distance compensation only delays in steps of the sample rate.
- * This is a bit less accurate since the delay time falls to the
- * nearest sample time, but it's far simpler as it doesn't have to
- * deal with phase offsets. This means at 48khz, for instance, the
- * distance delay will be in steps of about 7 millimeters.
- */
- delay = floorf((maxdist-conf->Speakers[i].Distance) / SPEEDOFSOUNDMETRESPERSEC *
- (ALfloat)srate + 0.5f);
- if(delay >= (ALfloat)MAX_DELAY_LENGTH)
- ERR("Delay for speaker \"%s\" exceeds buffer length (%f >= %u)\n",
- al_string_get_cstr(conf->Speakers[i].Name), delay, MAX_DELAY_LENGTH);
-
- dec->Delay[chan].Length = (ALuint)clampf(delay, 0.0f, (ALfloat)(MAX_DELAY_LENGTH-1));
- distgain[i] = conf->Speakers[i].Distance / maxdist;
- TRACE("Channel %u \"%s\" distance compensation: %d samples, %f gain\n", chan,
- al_string_get_cstr(conf->Speakers[i].Name), dec->Delay[chan].Length, distgain[i]
- );
- }
- }
-
memset(&dec->Matrix, 0, sizeof(dec->Matrix));
if(conf->FreqBands == 1)
{
@@ -356,7 +311,7 @@ void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALsizei chancount
else if(j == 5) gain = conf->HFOrderGain[3];
if((conf->ChanMask&(1<<l)))
dec->Matrix.Single[chan][j] = conf->HFMatrix[i][k++] / coeff_scale[l] *
- gain * distgain[i];
+ gain;
}
}
else
@@ -369,7 +324,7 @@ void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALsizei chancount
else if(j == 9) gain = conf->HFOrderGain[3];
if((conf->ChanMask&(1<<j)))
dec->Matrix.Single[chan][j] = conf->HFMatrix[i][k++] / coeff_scale[j] *
- gain * distgain[i];
+ gain;
}
}
}
@@ -400,8 +355,7 @@ void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALsizei chancount
else if(j == 5) gain = conf->HFOrderGain[3] * ratio;
if((conf->ChanMask&(1<<l)))
dec->Matrix.Dual[chan][FB_HighFreq][j] = conf->HFMatrix[i][k++] /
- coeff_scale[l] * gain *
- distgain[i];
+ coeff_scale[l] * gain;
}
for(j = 0,k = 0;j < MAX_AMBI2D_COEFFS;j++)
{
@@ -412,8 +366,7 @@ void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALsizei chancount
else if(j == 5) gain = conf->LFOrderGain[3] / ratio;
if((conf->ChanMask&(1<<l)))
dec->Matrix.Dual[chan][FB_LowFreq][j] = conf->LFMatrix[i][k++] /
- coeff_scale[l] * gain *
- distgain[i];
+ coeff_scale[l] * gain;
}
}
else
@@ -426,8 +379,7 @@ void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALsizei chancount
else if(j == 9) gain = conf->HFOrderGain[3] * ratio;
if((conf->ChanMask&(1<<j)))
dec->Matrix.Dual[chan][FB_HighFreq][j] = conf->HFMatrix[i][k++] /
- coeff_scale[j] * gain *
- distgain[i];
+ coeff_scale[j] * gain;
}
for(j = 0,k = 0;j < MAX_AMBI_COEFFS;j++)
{
@@ -437,8 +389,7 @@ void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALsizei chancount
else if(j == 9) gain = conf->LFOrderGain[3] / ratio;
if((conf->ChanMask&(1<<j)))
dec->Matrix.Dual[chan][FB_LowFreq][j] = conf->LFMatrix[i][k++] /
- coeff_scale[j] * gain *
- distgain[i];
+ coeff_scale[j] * gain;
}
}
}
@@ -471,29 +422,7 @@ void bformatdec_process(struct BFormatDec *dec, ALfloat (*restrict OutBuffer)[BU
SamplesToDo
);
- if(dec->Delay[chan].Length > 0)
- {
- const ALsizei base = dec->Delay[chan].Length;
- if(SamplesToDo >= base)
- {
- for(i = 0;i < base;i++)
- OutBuffer[chan][i] += dec->Delay[chan].Buffer[i];
- for(;i < SamplesToDo;i++)
- OutBuffer[chan][i] += dec->ChannelMix[i-base];
- memcpy(dec->Delay[chan].Buffer, &dec->ChannelMix[SamplesToDo-base],
- base*sizeof(ALfloat));
- }
- else
- {
- for(i = 0;i < SamplesToDo;i++)
- OutBuffer[chan][i] += dec->Delay[chan].Buffer[i];
- memmove(dec->Delay[chan].Buffer, dec->Delay[chan].Buffer+SamplesToDo,
- base - SamplesToDo);
- memcpy(dec->Delay[chan].Buffer+base-SamplesToDo, dec->ChannelMix,
- SamplesToDo*sizeof(ALfloat));
- }
- }
- else for(i = 0;i < SamplesToDo;i++)
+ for(i = 0;i < SamplesToDo;i++)
OutBuffer[chan][i] += dec->ChannelMix[i];
}
}
@@ -508,29 +437,7 @@ void bformatdec_process(struct BFormatDec *dec, ALfloat (*restrict OutBuffer)[BU
MixMatrixRow(dec->ChannelMix, dec->Matrix.Single[chan], InSamples,
dec->NumChannels, 0, SamplesToDo);
- if(dec->Delay[chan].Length > 0)
- {
- const ALsizei base = dec->Delay[chan].Length;
- if(SamplesToDo >= base)
- {
- for(i = 0;i < base;i++)
- OutBuffer[chan][i] += dec->Delay[chan].Buffer[i];
- for(;i < SamplesToDo;i++)
- OutBuffer[chan][i] += dec->ChannelMix[i-base];
- memcpy(dec->Delay[chan].Buffer, &dec->ChannelMix[SamplesToDo-base],
- base*sizeof(ALfloat));
- }
- else
- {
- for(i = 0;i < SamplesToDo;i++)
- OutBuffer[chan][i] += dec->Delay[chan].Buffer[i];
- memmove(dec->Delay[chan].Buffer, dec->Delay[chan].Buffer+SamplesToDo,
- base - SamplesToDo);
- memcpy(dec->Delay[chan].Buffer+base-SamplesToDo, dec->ChannelMix,
- SamplesToDo*sizeof(ALfloat));
- }
- }
- else for(i = 0;i < SamplesToDo;i++)
+ for(i = 0;i < SamplesToDo;i++)
OutBuffer[chan][i] += dec->ChannelMix[i];
}
}
@@ -570,6 +477,8 @@ void bformatdec_upSample(struct BFormatDec *dec, ALfloat (*restrict OutBuffer)[B
}
+#define INVALID_UPSAMPLE_INDEX INT_MAX
+
static ALsizei GetACNIndex(const BFChannelConfig *chans, ALsizei numchans, ALsizei acn)
{
ALsizei i;
diff --git a/Alc/bformatdec.h b/Alc/bformatdec.h
index 5f6e230d..97f36d0e 100644
--- a/Alc/bformatdec.h
+++ b/Alc/bformatdec.h
@@ -33,7 +33,7 @@ struct BFormatDec *bformatdec_alloc();
void bformatdec_free(struct BFormatDec *dec);
int bformatdec_getOrder(const struct BFormatDec *dec);
int bformatdec_isPeriphonic(const struct BFormatDec *dec);
-void bformatdec_reset(struct BFormatDec *dec, const struct AmbDecConf *conf, ALsizei chancount, ALuint srate, const ALsizei chanmap[MAX_OUTPUT_CHANNELS], int flags);
+void bformatdec_reset(struct BFormatDec *dec, const struct AmbDecConf *conf, ALsizei chancount, ALuint srate, const ALsizei chanmap[MAX_OUTPUT_CHANNELS]);
/* Decodes the ambisonic input to the given output channels. */
void bformatdec_process(struct BFormatDec *dec, ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALsizei OutChannels, const ALfloat (*restrict InSamples)[BUFFERSIZE], ALsizei SamplesToDo);
diff --git a/Alc/panning.c b/Alc/panning.c
index eb2ec0c8..80532bc4 100644
--- a/Alc/panning.c
+++ b/Alc/panning.c
@@ -693,13 +693,10 @@ static void InitCustomPanning(ALCdevice *device, const AmbDecConf *conf, const A
static void InitHQPanning(ALCdevice *device, const AmbDecConf *conf, const ALsizei speakermap[MAX_OUTPUT_CHANNELS])
{
const char *devname;
- int decflags = 0;
size_t count;
size_t i;
devname = al_string_get_cstr(device->DeviceName);
- if(GetConfigValueBool(devname, "decoder", "distance-comp", 1))
- decflags |= BFDF_DistanceComp;
if((conf->ChanMask&AMBI_PERIPHONIC_MASK))
{
@@ -731,8 +728,7 @@ static void InitHQPanning(ALCdevice *device, const AmbDecConf *conf, const ALsiz
(conf->ChanMask > 0xf) ? (conf->ChanMask > 0x1ff) ? "third" : "second" : "first",
(conf->ChanMask&AMBI_PERIPHONIC_MASK) ? " periphonic" : ""
);
- bformatdec_reset(device->AmbiDecoder, conf, count, device->Frequency,
- speakermap, decflags);
+ bformatdec_reset(device->AmbiDecoder, conf, count, device->Frequency, speakermap);
if(bformatdec_getOrder(device->AmbiDecoder) < 2)
{
@@ -759,6 +755,41 @@ static void InitHQPanning(ALCdevice *device, const AmbDecConf *conf, const ALsiz
}
device->FOAOut.CoeffCount = 0;
}
+
+ ALfloat maxdist = 0.0f;
+ for(i = 0;i < (size_t)conf->NumSpeakers;i++)
+ maxdist = maxf(maxdist, conf->Speakers[i].Distance);
+
+ if(GetConfigValueBool(devname, "decoder", "distance-comp", 1) && maxdist > 0.0f)
+ {
+ ALfloat srate = (ALfloat)device->Frequency;
+ for(i = 0;i < (size_t)conf->NumSpeakers;i++)
+ {
+ ALsizei chan = speakermap[i];
+ ALfloat delay;
+
+ /* Distance compensation only delays in steps of the sample rate.
+ * This is a bit less accurate since the delay time falls to the
+ * nearest sample time, but it's far simpler as it doesn't have to
+ * deal with phase offsets. This means at 48khz, for instance, the
+ * distance delay will be in steps of about 7 millimeters.
+ */
+ delay = floorf((maxdist-conf->Speakers[i].Distance) / SPEEDOFSOUNDMETRESPERSEC *
+ srate + 0.5f);
+ if(delay >= (ALfloat)MAX_DELAY_LENGTH)
+ ERR("Delay for speaker \"%s\" exceeds buffer length (%f >= %u)\n",
+ al_string_get_cstr(conf->Speakers[i].Name), delay, MAX_DELAY_LENGTH);
+
+ device->ChannelDelay[chan].Length = (ALsizei)clampf(
+ delay, 0.0f, (ALfloat)(MAX_DELAY_LENGTH-1)
+ );
+ device->ChannelDelay[chan].Gain = conf->Speakers[i].Distance / maxdist;
+ TRACE("Channel %u \"%s\" distance compensation: %d samples, %f gain\n", chan,
+ al_string_get_cstr(conf->Speakers[i].Name), device->ChannelDelay[chan].Length,
+ device->ChannelDelay[chan].Gain
+ );
+ }
+ }
}
static void InitHrtfPanning(ALCdevice *device, bool hoa_mode)
@@ -887,6 +918,13 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf
device->Dry.CoeffCount = 0;
device->Dry.NumChannels = 0;
+ memset(device->ChannelDelay, 0, sizeof(device->ChannelDelay));
+ for(i = 0;i < MAX_OUTPUT_CHANNELS;i++)
+ {
+ device->ChannelDelay[i].Gain = 1.0f;
+ device->ChannelDelay[i].Length = 0;
+ }
+
if(device->FmtChans != DevFmtStereo)
{
ALsizei speakermap[MAX_OUTPUT_CHANNELS];
diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h
index 947a16ba..bb8a57ce 100644
--- a/OpenAL32/Include/alMain.h
+++ b/OpenAL32/Include/alMain.h
@@ -603,6 +603,15 @@ typedef struct HrtfEntry {
TYPEDEF_VECTOR(HrtfEntry, vector_HrtfEntry)
+/* Maximum delay in samples for speaker distance compensation. */
+#define MAX_DELAY_LENGTH 128
+
+typedef struct DistanceComp {
+ ALfloat Gain;
+ ALsizei Length; /* Valid range is [0...MAX_DELAY_LENGTH). */
+ alignas(16) ALfloat Buffer[MAX_DELAY_LENGTH];
+} DistanceComp;
+
/* Size for temporary storage of buffer data, in ALfloats. Larger values need
* more memory, while smaller values may need more iterations. The value needs
* to be a sensible size, however, as it constrains the max stepping value used
@@ -723,6 +732,9 @@ struct ALCdevice_struct
ALsizei NumChannels;
} RealOut;
+ /* Delay buffers used to compensate for speaker distances. */
+ DistanceComp ChannelDelay[MAX_OUTPUT_CHANNELS];
+
/* Running count of the mixer invocations, in 31.1 fixed point. This
* actually increments *twice* when mixing, first at the start and then at
* the end, so the bottom bit indicates if the device is currently mixing