Implement NFC filters for Ambisonic rendering
NFC filters currently only work when rendering to ambisonic buffers, which includes HQ rendering and ambisonic output. There are two new config options: 'decoder/nfc' (default on) enables or disables use of NFC filters globally, and 'decoder/nfc-ref-delay' (default 0) specifies the reference delay parameter for NFC-HOA rendering with ambisonic output (a value of 0 disables NFC). Currently, NFC filters rely on having an appropriate value set for AL_METERS_PER_UNIT to get the correct scaling. HQ rendering uses the averaged speaker distances as a control/reference, and currently doesn't correct for individual speaker distances (if the speakers are all equidistant, this is fine, otherwise per-speaker correction should be done as well).
This commit is contained in:
parent
d9b1995e95
commit
583d431947
20
Alc/ALc.c
20
Alc/ALc.c
@ -2310,6 +2310,24 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList)
|
||||
}
|
||||
}
|
||||
AllocateVoices(context, context->MaxVoices, old_sends);
|
||||
for(pos = 0;pos < context->VoiceCount;pos++)
|
||||
{
|
||||
ALvoice *voice = context->Voices[pos];
|
||||
if(!voice->Source) continue;
|
||||
|
||||
if(device->AvgSpeakerDist > 0.0f)
|
||||
{
|
||||
/* Reinitialize the NFC filters for new parameters. */
|
||||
ALfloat w1 = SPEEDOFSOUNDMETRESPERSEC /
|
||||
(device->AvgSpeakerDist * device->Frequency);
|
||||
for(i = 0;i < voice->NumChannels;i++)
|
||||
{
|
||||
NfcFilterCreate1(&voice->Direct.Params[i].NFCtrlFilter[0], 0.0f, w1);
|
||||
NfcFilterCreate2(&voice->Direct.Params[i].NFCtrlFilter[1], 0.0f, w1);
|
||||
NfcFilterCreate3(&voice->Direct.Params[i].NFCtrlFilter[2], 0.0f, w1);
|
||||
}
|
||||
}
|
||||
}
|
||||
UnlockUIntMapRead(&context->SourceMap);
|
||||
|
||||
UpdateListenerProps(context);
|
||||
@ -3755,6 +3773,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName)
|
||||
device->FOAOut.NumChannels = 0;
|
||||
device->RealOut.Buffer = NULL;
|
||||
device->RealOut.NumChannels = 0;
|
||||
device->AvgSpeakerDist = 0.0f;
|
||||
|
||||
ATOMIC_INIT(&device->ContextList, NULL);
|
||||
|
||||
@ -4271,6 +4290,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcLoopbackOpenDeviceSOFT(const ALCchar *deviceN
|
||||
device->FOAOut.NumChannels = 0;
|
||||
device->RealOut.Buffer = NULL;
|
||||
device->RealOut.NumChannels = 0;
|
||||
device->AvgSpeakerDist = 0.0f;
|
||||
|
||||
ATOMIC_INIT(&device->ContextList, NULL);
|
||||
|
||||
|
64
Alc/ALu.c
64
Alc/ALu.c
@ -496,6 +496,7 @@ static void CalcNonAttnSourceParams(ALvoice *voice, const struct ALsourceProps *
|
||||
break;
|
||||
}
|
||||
|
||||
voice->Flags &= ~(VOICE_IS_HRTF | VOICE_HAS_NFC);
|
||||
if(isbformat)
|
||||
{
|
||||
ALfloat N[3], V[3], U[3];
|
||||
@ -535,6 +536,17 @@ static void CalcNonAttnSourceParams(ALvoice *voice, const struct ALsourceProps *
|
||||
for(c = 0;c < num_channels;c++)
|
||||
ComputeFirstOrderGains(Device->FOAOut, matrix.m[c], DryGain,
|
||||
voice->Direct.Params[c].Gains.Target);
|
||||
if(Device->AvgSpeakerDist > 0.0f)
|
||||
{
|
||||
/* NOTE: The NFCtrlFilters were created with a w0 of 0, which is
|
||||
* what we want for FOA input. So there's nothing to adjust.
|
||||
*/
|
||||
voice->Direct.ChannelsPerOrder[0] = 1;
|
||||
voice->Direct.ChannelsPerOrder[1] = mini(voice->Direct.Channels-1, 3);
|
||||
voice->Direct.ChannelsPerOrder[2] = 0;
|
||||
voice->Direct.ChannelsPerOrder[3] = 0;
|
||||
voice->Flags |= VOICE_HAS_NFC;
|
||||
}
|
||||
|
||||
for(i = 0;i < NumSends;i++)
|
||||
{
|
||||
@ -553,8 +565,6 @@ static void CalcNonAttnSourceParams(ALvoice *voice, const struct ALsourceProps *
|
||||
voice->Send[i].Params[c].Gains.Target[j] = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
voice->IsHrtf = AL_FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -592,8 +602,6 @@ static void CalcNonAttnSourceParams(ALvoice *voice, const struct ALsourceProps *
|
||||
voice->Send[i].Params[c].Gains.Target[j] = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
voice->IsHrtf = AL_FALSE;
|
||||
}
|
||||
else if(Device->Render_Mode == HrtfRender)
|
||||
{
|
||||
@ -647,7 +655,7 @@ static void CalcNonAttnSourceParams(ALvoice *voice, const struct ALsourceProps *
|
||||
}
|
||||
}
|
||||
|
||||
voice->IsHrtf = AL_TRUE;
|
||||
voice->Flags |= VOICE_IS_HRTF;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -694,8 +702,6 @@ static void CalcNonAttnSourceParams(ALvoice *voice, const struct ALsourceProps *
|
||||
voice->Send[i].Params[c].Gains.Target[j] = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
voice->IsHrtf = AL_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1064,6 +1070,7 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALsourceProps *pro
|
||||
voice->Step = maxi(fastf2i(Pitch*FRACTIONONE + 0.5f), 1);
|
||||
BsincPrepare(voice->Step, &voice->ResampleState.bsinc);
|
||||
|
||||
voice->Flags &= ~(VOICE_IS_HRTF | VOICE_HAS_NFC);
|
||||
if(Device->Render_Mode == HrtfRender)
|
||||
{
|
||||
/* Full HRTF rendering. Skip the virtual channels and render to the
|
||||
@ -1115,7 +1122,7 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALsourceProps *pro
|
||||
voice->Send[i].Params[0].Gains.Target[j] = 0.0f;
|
||||
}
|
||||
|
||||
voice->IsHrtf = AL_TRUE;
|
||||
voice->Flags |= VOICE_IS_HRTF;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1128,10 +1135,49 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALsourceProps *pro
|
||||
/* Get the localized direction, and compute panned gains. */
|
||||
if(Distance > FLT_EPSILON)
|
||||
{
|
||||
if(Device->AvgSpeakerDist > 0.0f && MetersPerUnit > 0.0f)
|
||||
{
|
||||
ALfloat w0 = SPEEDOFSOUNDMETRESPERSEC /
|
||||
(Distance*MetersPerUnit * (ALfloat)Device->Frequency);
|
||||
ALfloat w1 = SPEEDOFSOUNDMETRESPERSEC /
|
||||
(Device->AvgSpeakerDist * (ALfloat)Device->Frequency);
|
||||
/* Clamp w0 for really close distances, to prevent excessive
|
||||
* bass.
|
||||
*/
|
||||
w0 = minf(w0, w1*4.0f);
|
||||
|
||||
NfcFilterAdjust1(&voice->Direct.Params[0].NFCtrlFilter[0], w0);
|
||||
NfcFilterAdjust2(&voice->Direct.Params[0].NFCtrlFilter[1], w0);
|
||||
NfcFilterAdjust3(&voice->Direct.Params[0].NFCtrlFilter[2], w0);
|
||||
|
||||
for(i = 0;i < MAX_AMBI_ORDER+1;i++)
|
||||
voice->Direct.ChannelsPerOrder[i] = Device->Dry.NumChannelsPerOrder[i];
|
||||
voice->Flags |= VOICE_HAS_NFC;
|
||||
}
|
||||
|
||||
dir[0] = -SourceToListener.v[0];
|
||||
dir[1] = -SourceToListener.v[1];
|
||||
dir[2] = -SourceToListener.v[2] * ZScale;
|
||||
}
|
||||
else if(Device->AvgSpeakerDist > 0.0f)
|
||||
{
|
||||
/* If the source distance is 0, set w0 to w1 to act as a pass-
|
||||
* through. We still want to pass the signal through the filters so
|
||||
* they keep an appropriate history, in case the source moves away
|
||||
* from the listener.
|
||||
*/
|
||||
ALfloat w0 = SPEEDOFSOUNDMETRESPERSEC /
|
||||
(Device->AvgSpeakerDist * (ALfloat)Device->Frequency);
|
||||
|
||||
NfcFilterAdjust1(&voice->Direct.Params[0].NFCtrlFilter[0], w0);
|
||||
NfcFilterAdjust2(&voice->Direct.Params[0].NFCtrlFilter[1], w0);
|
||||
NfcFilterAdjust3(&voice->Direct.Params[0].NFCtrlFilter[2], w0);
|
||||
|
||||
for(i = 0;i < MAX_AMBI_ORDER+1;i++)
|
||||
voice->Direct.ChannelsPerOrder[i] = Device->Dry.NumChannelsPerOrder[i];
|
||||
voice->Flags |= VOICE_HAS_NFC;
|
||||
}
|
||||
|
||||
if(radius > Distance)
|
||||
spread = F_TAU - Distance/radius*F_PI;
|
||||
else if(Distance > FLT_EPSILON)
|
||||
@ -1160,8 +1206,6 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALsourceProps *pro
|
||||
for(j = 0;j < MAX_EFFECT_CHANNELS;j++)
|
||||
voice->Send[i].Params[0].Gains.Target[j] = 0.0f;
|
||||
}
|
||||
|
||||
voice->IsHrtf = AL_FALSE;
|
||||
}
|
||||
|
||||
{
|
||||
|
55
Alc/mixer.c
55
Alc/mixer.c
@ -545,15 +545,60 @@ ALboolean MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALsizei
|
||||
&parms->LowPass, &parms->HighPass, Device->FilteredData,
|
||||
ResampledData, DstBufferSize, parms->FilterType
|
||||
);
|
||||
if(!voice->IsHrtf)
|
||||
if(!(voice->Flags&VOICE_IS_HRTF))
|
||||
{
|
||||
if(!Counter)
|
||||
memcpy(parms->Gains.Current, parms->Gains.Target,
|
||||
sizeof(parms->Gains.Current));
|
||||
MixSamples(samples, voice->Direct.Channels, voice->Direct.Buffer,
|
||||
parms->Gains.Current, parms->Gains.Target, Counter, OutPos,
|
||||
DstBufferSize
|
||||
);
|
||||
if(!(voice->Flags&VOICE_HAS_NFC))
|
||||
MixSamples(samples, voice->Direct.Channels, voice->Direct.Buffer,
|
||||
parms->Gains.Current, parms->Gains.Target, Counter, OutPos,
|
||||
DstBufferSize
|
||||
);
|
||||
else
|
||||
{
|
||||
ALfloat *nfcsamples = Device->NFCtrlData;
|
||||
ALsizei chanoffset = 0;
|
||||
MixSamples(samples,
|
||||
voice->Direct.ChannelsPerOrder[0], voice->Direct.Buffer,
|
||||
parms->Gains.Current, parms->Gains.Target, Counter, OutPos,
|
||||
DstBufferSize
|
||||
);
|
||||
chanoffset += voice->Direct.ChannelsPerOrder[0];
|
||||
if(voice->Direct.ChannelsPerOrder[1] > 0)
|
||||
{
|
||||
NfcFilterUpdate1(&parms->NFCtrlFilter[0], nfcsamples, samples,
|
||||
DstBufferSize);
|
||||
MixSamples(nfcsamples,
|
||||
voice->Direct.ChannelsPerOrder[1], voice->Direct.Buffer+chanoffset,
|
||||
parms->Gains.Current+chanoffset, parms->Gains.Target+chanoffset,
|
||||
Counter, OutPos, DstBufferSize
|
||||
);
|
||||
chanoffset += voice->Direct.ChannelsPerOrder[1];
|
||||
}
|
||||
if(voice->Direct.ChannelsPerOrder[2] > 0)
|
||||
{
|
||||
NfcFilterUpdate2(&parms->NFCtrlFilter[1], nfcsamples, samples,
|
||||
DstBufferSize);
|
||||
MixSamples(nfcsamples,
|
||||
voice->Direct.ChannelsPerOrder[2], voice->Direct.Buffer+chanoffset,
|
||||
parms->Gains.Current+chanoffset, parms->Gains.Target+chanoffset,
|
||||
Counter, OutPos, DstBufferSize
|
||||
);
|
||||
chanoffset += voice->Direct.ChannelsPerOrder[2];
|
||||
}
|
||||
if(voice->Direct.ChannelsPerOrder[3] > 0)
|
||||
{
|
||||
NfcFilterUpdate3(&parms->NFCtrlFilter[2], nfcsamples, samples,
|
||||
DstBufferSize);
|
||||
MixSamples(nfcsamples,
|
||||
voice->Direct.ChannelsPerOrder[3], voice->Direct.Buffer+chanoffset,
|
||||
parms->Gains.Current+chanoffset, parms->Gains.Target+chanoffset,
|
||||
Counter, OutPos, DstBufferSize
|
||||
);
|
||||
chanoffset += voice->Direct.ChannelsPerOrder[3];
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
172
Alc/panning.c
172
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++)
|
||||
{
|
||||
|
@ -726,6 +726,7 @@ struct ALCdevice_struct
|
||||
alignas(16) ALfloat SourceData[BUFFERSIZE];
|
||||
alignas(16) ALfloat ResampledData[BUFFERSIZE];
|
||||
alignas(16) ALfloat FilteredData[BUFFERSIZE];
|
||||
alignas(16) ALfloat NFCtrlData[BUFFERSIZE];
|
||||
|
||||
/* The "dry" path corresponds to the main output. */
|
||||
struct {
|
||||
@ -738,6 +739,7 @@ struct ALCdevice_struct
|
||||
|
||||
ALfloat (*Buffer)[BUFFERSIZE];
|
||||
ALsizei NumChannels;
|
||||
ALsizei NumChannelsPerOrder[MAX_AMBI_ORDER+1];
|
||||
} Dry;
|
||||
|
||||
/* First-order ambisonics output, to be upsampled to the dry buffer if different. */
|
||||
@ -760,6 +762,11 @@ struct ALCdevice_struct
|
||||
ALsizei NumChannels;
|
||||
} RealOut;
|
||||
|
||||
/* The average speaker distance as determined by the ambdec configuration
|
||||
* (or alternatively, by the NFC-HOA reference delay). Only used for NFC.
|
||||
*/
|
||||
ALfloat AvgSpeakerDist;
|
||||
|
||||
/* Delay buffers used to compensate for speaker distances. */
|
||||
DistanceComp ChannelDelay[MAX_OUTPUT_CHANNELS];
|
||||
|
||||
|
@ -17,6 +17,7 @@
|
||||
|
||||
#include "hrtf.h"
|
||||
#include "align.h"
|
||||
#include "nfcfilter.h"
|
||||
#include "math_defs.h"
|
||||
|
||||
|
||||
@ -129,6 +130,8 @@ typedef struct DirectParams {
|
||||
ALfilterState LowPass;
|
||||
ALfilterState HighPass;
|
||||
|
||||
NfcFilter NFCtrlFilter[MAX_AMBI_ORDER];
|
||||
|
||||
struct {
|
||||
HrtfParams Current;
|
||||
HrtfParams Target;
|
||||
@ -152,6 +155,9 @@ typedef struct SendParams {
|
||||
} Gains;
|
||||
} SendParams;
|
||||
|
||||
#define VOICE_IS_HRTF (1<<0)
|
||||
#define VOICE_HAS_NFC (1<<1)
|
||||
|
||||
typedef struct ALvoice {
|
||||
struct ALsourceProps *Props;
|
||||
|
||||
@ -182,7 +188,7 @@ typedef struct ALvoice {
|
||||
/* If not 'moving', gain/coefficients are set directly without fading. */
|
||||
ALboolean Moving;
|
||||
|
||||
ALboolean IsHrtf;
|
||||
ALuint Flags;
|
||||
|
||||
ALuint Offset; /* Number of output samples mixed since starting. */
|
||||
|
||||
@ -195,6 +201,7 @@ typedef struct ALvoice {
|
||||
|
||||
ALfloat (*Buffer)[BUFFERSIZE];
|
||||
ALsizei Channels;
|
||||
ALsizei ChannelsPerOrder[MAX_AMBI_ORDER+1];
|
||||
} Direct;
|
||||
|
||||
struct {
|
||||
|
@ -3084,6 +3084,7 @@ ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state)
|
||||
voice->Step = 0;
|
||||
|
||||
voice->Moving = AL_FALSE;
|
||||
voice->Flags = 0;
|
||||
for(i = 0;i < MAX_INPUT_CHANNELS;i++)
|
||||
{
|
||||
ALsizei j;
|
||||
@ -3095,6 +3096,17 @@ ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state)
|
||||
voice->Direct.Params[i].Hrtf.State.Values[j][1] = 0.0f;
|
||||
}
|
||||
}
|
||||
if(device->AvgSpeakerDist > 0.0f)
|
||||
{
|
||||
ALfloat w1 = SPEEDOFSOUNDMETRESPERSEC /
|
||||
(device->AvgSpeakerDist * device->Frequency);
|
||||
for(i = 0;i < voice->NumChannels;i++)
|
||||
{
|
||||
NfcFilterCreate1(&voice->Direct.Params[i].NFCtrlFilter[0], 0.0f, w1);
|
||||
NfcFilterCreate2(&voice->Direct.Params[i].NFCtrlFilter[1], 0.0f, w1);
|
||||
NfcFilterCreate3(&voice->Direct.Params[i].NFCtrlFilter[2], 0.0f, w1);
|
||||
}
|
||||
}
|
||||
|
||||
ATOMIC_STORE(&voice->Source, Source, almemory_order_relaxed);
|
||||
ATOMIC_STORE(&voice->Playing, true, almemory_order_release);
|
||||
|
Loading…
x
Reference in New Issue
Block a user