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:
Chris Robinson 2017-03-10 04:35:32 -08:00
parent d9b1995e95
commit 583d431947
7 changed files with 262 additions and 77 deletions

View File

@ -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);

View File

@ -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;
}
{

View File

@ -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
{

View File

@ -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++)
{

View File

@ -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];

View File

@ -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 {

View File

@ -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);