aboutsummaryrefslogtreecommitdiffstats
path: root/Alc/panning.c
diff options
context:
space:
mode:
Diffstat (limited to 'Alc/panning.c')
-rw-r--r--Alc/panning.c172
1 files changed, 111 insertions, 61 deletions
diff --git a/Alc/panning.c b/Alc/panning.c
index c4d3e43f..6315328a 100644
--- a/Alc/panning.c
+++ b/Alc/panning.c
@@ -487,6 +487,88 @@ static const ChannelMap MonoCfg[1] = {
{ BackRight, { 2.04124145e-1f, -1.08880247e-1f, 0.0f, -1.88586120e-1f, 1.29099444e-1f, 0.0f, 0.0f, 0.0f, 7.45355993e-2f, -3.73460789e-2f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.00000000e+0f } },
};
+static void InitNearFieldCtrl(ALCdevice *device, ALfloat ctrl_dist, ALsizei order, bool periphonic)
+{
+ const char *devname = al_string_get_cstr(device->DeviceName);
+ ALsizei i;
+
+ if(GetConfigValueBool(devname, "decoder", "nfc", 1) && ctrl_dist > 0.0f)
+ {
+ /* NFC is only used when AvgSpeakerDist is greater than 0, and
+ * METERS_PER_UNIT is also greater than 0. In addition, NFC can only be
+ * used when rendering to an ambisonic buffer.
+ */
+ device->AvgSpeakerDist = ctrl_dist;
+
+ device->Dry.NumChannelsPerOrder[0] = 1;
+ if(periphonic)
+ for(i = 1;i < order+1;i++)
+ device->Dry.NumChannelsPerOrder[i] = (i+1)*(i+1) - i*i;
+ else
+ for(i = 1;i < order+1;i++)
+ device->Dry.NumChannelsPerOrder[i] = (i*2+1) - ((i-1)*2+1);
+ for(;i < MAX_AMBI_ORDER+1;i++)
+ device->Dry.NumChannelsPerOrder[i] = 0;
+ }
+}
+
+static void InitDistanceComp(ALCdevice *device, const AmbDecConf *conf, const ALsizei speakermap[MAX_OUTPUT_CHANNELS])
+{
+ const char *devname = al_string_get_cstr(device->DeviceName);
+ ALfloat maxdist = 0.0f;
+ ALsizei total = 0;
+ ALsizei i;
+
+ for(i = 0;i < 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 < 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
+ );
+
+ /* Round up to the next 4th sample, so each channel buffer starts
+ * 16-byte aligned.
+ */
+ total += RoundUp(device->ChannelDelay[chan].Length, 4);
+ }
+ }
+
+ if(total > 0)
+ {
+ device->ChannelDelay[0].Buffer = al_calloc(16, total * sizeof(ALfloat));
+ for(i = 1;i < MAX_OUTPUT_CHANNELS;i++)
+ {
+ size_t len = RoundUp(device->ChannelDelay[i-1].Length, 4);
+ device->ChannelDelay[i].Buffer = device->ChannelDelay[i-1].Buffer + len;
+ }
+ }
+}
+
static void InitPanning(ALCdevice *device)
{
const ChannelMap *chanmap = NULL;
@@ -546,10 +628,12 @@ static void InitPanning(ALCdevice *device)
if(device->FmtChans >= DevFmtAmbi1 && device->FmtChans <= DevFmtAmbi3)
{
+ const char *devname = al_string_get_cstr(device->DeviceName);
const ALsizei *acnmap = (device->AmbiLayout == AmbiLayout_FuMa) ? FuMa2ACN : ACN2ACN;
const ALfloat *n3dscale = (device->AmbiScale == AmbiNorm_FuMa) ? FuMa2N3DScale :
(device->AmbiScale == AmbiNorm_SN3D) ? SN3D2N3DScale :
/*(device->AmbiScale == AmbiNorm_N3D) ?*/ UnitScale;
+ ALfloat nfc_delay = 0.0f;
count = (device->FmtChans == DevFmtAmbi3) ? 16 :
(device->FmtChans == DevFmtAmbi2) ? 9 :
@@ -585,6 +669,16 @@ static void InitPanning(ALCdevice *device)
ambiup_reset(device->AmbiUp, device);
}
+
+ if(ConfigValueFloat(devname, "decoder", "nfc-ref-delay", &nfc_delay))
+ {
+ nfc_delay = clampf(nfc_delay, 0.001f, 1000.0f);
+ InitNearFieldCtrl(device, nfc_delay * SPEEDOFSOUNDMETRESPERSEC,
+ (device->FmtChans == DevFmtAmbi3) ? 3 :
+ (device->FmtChans == DevFmtAmbi2) ? 2 : 1,
+ true
+ );
+ }
}
else
{
@@ -612,63 +706,6 @@ static void InitPanning(ALCdevice *device)
device->RealOut.NumChannels = 0;
}
-static void InitDistanceComp(ALCdevice *device, const AmbDecConf *conf, const ALsizei speakermap[MAX_OUTPUT_CHANNELS])
-{
- const char *devname = al_string_get_cstr(device->DeviceName);
- ALfloat maxdist = 0.0f;
- ALsizei total = 0;
- ALsizei i;
-
- for(i = 0;i < 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 < 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
- );
-
- /* Round up to the next 4th sample, so each channel buffer starts
- * 16-byte aligned.
- */
- total += RoundUp(device->ChannelDelay[chan].Length, 4);
- }
- }
-
- if(total > 0)
- {
- device->ChannelDelay[0].Buffer = al_calloc(16, total * sizeof(ALfloat));
- for(i = 1;i < MAX_OUTPUT_CHANNELS;i++)
- {
- size_t len = RoundUp(device->ChannelDelay[i-1].Length, 4);
- device->ChannelDelay[i].Buffer = device->ChannelDelay[i-1].Buffer + len;
- }
- }
-}
-
static void InitCustomPanning(ALCdevice *device, const AmbDecConf *conf, const ALsizei speakermap[MAX_OUTPUT_CHANNELS])
{
ChannelMap chanmap[MAX_OUTPUT_CHANNELS];
@@ -756,8 +793,9 @@ static void InitCustomPanning(ALCdevice *device, const AmbDecConf *conf, const A
static void InitHQPanning(ALCdevice *device, const AmbDecConf *conf, const ALsizei speakermap[MAX_OUTPUT_CHANNELS])
{
- size_t count;
- size_t i;
+ ALfloat avg_dist;
+ ALsizei count;
+ ALsizei i;
if((conf->ChanMask&AMBI_PERIPHONIC_MASK))
{
@@ -825,6 +863,15 @@ static void InitHQPanning(ALCdevice *device, const AmbDecConf *conf, const ALsiz
device->RealOut.NumChannels = ChannelsFromDevFmt(device->FmtChans);
+ avg_dist = 0.0f;
+ for(i = 0;i < conf->NumSpeakers;i++)
+ avg_dist += conf->Speakers[i].Distance;
+ avg_dist /= (ALfloat)conf->NumSpeakers;
+ InitNearFieldCtrl(device, avg_dist,
+ (conf->ChanMask > 0x1ff) ? 3 : (conf->ChanMask > 0xf) ? 2 : 1,
+ !!(conf->ChanMask&AMBI_PERIPHONIC_MASK)
+ );
+
InitDistanceComp(device, conf, speakermap);
}
@@ -879,8 +926,8 @@ static void InitHrtfPanning(ALCdevice *device, bool hoa_mode)
{ { 1.43315266e-001f, 0.00000000e+000f, -1.90399923e-001f, 0.00000000e+000f, 0.00000000e+000f, 0.00000000e+000f, 1.18020996e-001f, 0.00000000e+000f, 0.00000000e+000f }, { 7.26741039e-002f, 0.00000000e+000f, -1.24646009e-001f, 0.00000000e+000f, 0.00000000e+000f, 0.00000000e+000f, 1.49618920e-001f, 0.00000000e+000f, 0.00000000e+000f } },
};
const ALfloat (*AmbiMatrix)[2][MAX_AMBI_COEFFS] = hoa_mode ? AmbiMatrixHOA : AmbiMatrixFOA;
- size_t count = hoa_mode ? 9 : 4;
- size_t i;
+ ALsizei count = hoa_mode ? 9 : 4;
+ ALsizei i;
static_assert(9 <= COUNTOF(device->Hrtf.Coeffs), "ALCdevice::Hrtf.Values/Coeffs size is too small");
static_assert(COUNTOF(AmbiPoints) <= HRTF_AMBI_MAX_CHANNELS, "HRTF_AMBI_MAX_CHANNELS is too small");
@@ -960,7 +1007,10 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf
memset(&device->Dry.Ambi, 0, sizeof(device->Dry.Ambi));
device->Dry.CoeffCount = 0;
device->Dry.NumChannels = 0;
+ for(i = 0;i < MAX_AMBI_ORDER+1;i++)
+ device->Dry.NumChannelsPerOrder[i] = 0;
+ device->AvgSpeakerDist = 0.0f;
memset(device->ChannelDelay, 0, sizeof(device->ChannelDelay));
for(i = 0;i < MAX_OUTPUT_CHANNELS;i++)
{