Track the virtual and real output buffers ecplicitly

This commit is contained in:
Chris Robinson 2016-03-09 22:57:38 -08:00
parent 3b9fe27cbe
commit 3e2672ec9f
4 changed files with 91 additions and 47 deletions

View File

@ -1855,6 +1855,10 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList)
al_free(device->DryBuffer);
device->DryBuffer = NULL;
device->VirtOut.Buffer = NULL;
device->VirtOut.NumChannels = 0;
device->RealOut.Buffer = NULL;
device->RealOut.NumChannels = 0;
UpdateClockBase(device);
@ -2124,6 +2128,21 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList)
return ALC_INVALID_DEVICE;
}
if(device->Hrtf || device->Uhj_Encoder)
{
device->VirtOut.Buffer = device->DryBuffer;
device->VirtOut.NumChannels = device->NumChannels;
device->RealOut.Buffer = device->DryBuffer + device->NumChannels;
device->RealOut.NumChannels = 2;
}
else
{
device->VirtOut.Buffer = NULL;
device->VirtOut.NumChannels = 0;
device->RealOut.Buffer = device->DryBuffer;
device->RealOut.NumChannels = device->NumChannels;
}
SetMixerFPUMode(&oldMode);
V0(device->Backend,lock)();
context = ATOMIC_LOAD(&device->ContextList);
@ -2261,6 +2280,10 @@ static ALCvoid FreeDevice(ALCdevice *device)
al_free(device->DryBuffer);
device->DryBuffer = NULL;
device->VirtOut.Buffer = NULL;
device->VirtOut.NumChannels = 0;
device->RealOut.Buffer = NULL;
device->RealOut.NumChannels = 0;
al_free(device);
}
@ -3361,6 +3384,10 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName)
device->Render_Mode = NormalRender;
AL_STRING_INIT(device->DeviceName);
device->DryBuffer = NULL;
device->VirtOut.Buffer = NULL;
device->VirtOut.NumChannels = 0;
device->RealOut.Buffer = NULL;
device->RealOut.NumChannels = 0;
ATOMIC_INIT(&device->ContextList, NULL);
@ -3616,6 +3643,10 @@ ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *deviceName,
AL_STRING_INIT(device->DeviceName);
device->DryBuffer = NULL;
device->VirtOut.Buffer = NULL;
device->VirtOut.NumChannels = 0;
device->RealOut.Buffer = NULL;
device->RealOut.NumChannels = 0;
InitUIntMap(&device->BufferMap, ~0);
InitUIntMap(&device->EffectMap, ~0);
@ -3806,6 +3837,10 @@ ALC_API ALCdevice* ALC_APIENTRY alcLoopbackOpenDeviceSOFT(const ALCchar *deviceN
device->Render_Mode = NormalRender;
AL_STRING_INIT(device->DeviceName);
device->DryBuffer = NULL;
device->VirtOut.Buffer = NULL;
device->VirtOut.NumChannels = 0;
device->RealOut.Buffer = NULL;
device->RealOut.NumChannels = 0;
ATOMIC_INIT(&device->ContextList, NULL);

View File

@ -581,8 +581,8 @@ ALvoid CalcNonAttnSourceParams(ALvoice *voice, const ALsource *ALSource, const A
* channels and write FrontLeft and FrontRight inputs to the
* first and second outputs.
*/
voice->Direct.OutBuffer += voice->Direct.OutChannels;
voice->Direct.OutChannels = 2;
voice->Direct.OutBuffer = Device->RealOut.Buffer;
voice->Direct.OutChannels = Device->RealOut.NumChannels;
for(c = 0;c < num_channels;c++)
{
for(j = 0;j < MAX_OUTPUT_CHANNELS;j++)
@ -632,8 +632,8 @@ ALvoid CalcNonAttnSourceParams(ALvoice *voice, const ALsource *ALSource, const A
/* Full HRTF rendering. Skip the virtual channels and render each
* input channel to the real outputs.
*/
voice->Direct.OutBuffer += voice->Direct.OutChannels;
voice->Direct.OutChannels = 2;
voice->Direct.OutBuffer = Device->RealOut.Buffer;
voice->Direct.OutChannels = Device->RealOut.NumChannels;
for(c = 0;c < num_channels;c++)
{
if(chans[c].channel == LFE)
@ -1131,8 +1131,8 @@ ALvoid CalcSourceParams(ALvoice *voice, const ALsource *ALSource, const ALCconte
ALfloat dirfact = 1.0f;
ALfloat coeffs[MAX_AMBI_COEFFS];
voice->Direct.OutBuffer += voice->Direct.OutChannels;
voice->Direct.OutChannels = 2;
voice->Direct.OutBuffer = Device->RealOut.Buffer;
voice->Direct.OutChannels = Device->RealOut.NumChannels;
if(Distance > FLT_EPSILON)
{
@ -1393,26 +1393,13 @@ ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size)
while(size > 0)
{
ALfloat (*OutBuffer)[BUFFERSIZE];
ALuint OutChannels;
IncrementRef(&device->MixCount);
OutBuffer = device->DryBuffer;
OutChannels = device->NumChannels;
SamplesToDo = minu(size, BUFFERSIZE);
for(c = 0;c < OutChannels;c++)
memset(OutBuffer[c], 0, SamplesToDo*sizeof(ALfloat));
if(device->Hrtf || device->Uhj_Encoder)
{
/* Set OutBuffer/OutChannels to correspond to the actual output
* with HRTF. Make sure to clear them too. */
OutBuffer += OutChannels;
OutChannels = 2;
for(c = 0;c < OutChannels;c++)
memset(OutBuffer[c], 0, SamplesToDo*sizeof(ALfloat));
}
for(c = 0;c < device->VirtOut.NumChannels;c++)
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));
V0(device->Backend,lock)();
@ -1495,12 +1482,13 @@ ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size)
ALuint irsize = GetHrtfIrSize(device->Hrtf);
MixHrtfParams hrtfparams;
memset(&hrtfparams, 0, sizeof(hrtfparams));
for(c = 0;c < device->NumChannels;c++)
for(c = 0;c < device->VirtOut.NumChannels;c++)
{
hrtfparams.Current = &device->Hrtf_Params[c];
hrtfparams.Target = &device->Hrtf_Params[c];
HrtfMix(OutBuffer, device->DryBuffer[c], 0, device->Hrtf_Offset,
0, irsize, &hrtfparams, &device->Hrtf_State[c], SamplesToDo
HrtfMix(device->RealOut.Buffer, device->VirtOut.Buffer[c], 0,
device->Hrtf_Offset, 0, irsize, &hrtfparams,
&device->Hrtf_State[c], SamplesToDo
);
}
device->Hrtf_Offset += SamplesToDo;
@ -1510,7 +1498,8 @@ ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size)
if(device->Uhj_Encoder)
{
/* Encode to stereo-compatible 2-channel UHJ output. */
EncodeUhj2(device->Uhj_Encoder, OutBuffer, device->DryBuffer, SamplesToDo);
EncodeUhj2(device->Uhj_Encoder, device->RealOut.Buffer,
device->VirtOut.Buffer, SamplesToDo);
}
if(device->Bs2b)
{
@ -1518,17 +1507,20 @@ ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size)
for(i = 0;i < SamplesToDo;i++)
{
float samples[2];
samples[0] = OutBuffer[0][i];
samples[1] = OutBuffer[1][i];
samples[0] = device->RealOut.Buffer[0][i];
samples[1] = device->RealOut.Buffer[1][i];
bs2b_cross_feed(device->Bs2b, samples);
OutBuffer[0][i] = samples[0];
OutBuffer[1][i] = samples[1];
device->RealOut.Buffer[0][i] = samples[0];
device->RealOut.Buffer[1][i] = samples[1];
}
}
}
if(buffer)
{
ALfloat (*OutBuffer)[BUFFERSIZE] = device->RealOut.Buffer;
ALuint OutChannels = device->RealOut.NumChannels;;
#define WRITE(T, a, b, c, d) do { \
Write_##T((a), (b), (c), (d)); \
buffer = (T*)buffer + (c)*(d); \

View File

@ -364,6 +364,9 @@ static ALboolean ALreverbState_deviceUpdate(ALreverbState *State, ALCdevice *Dev
if(!AllocLines(frequency, State))
return AL_FALSE;
/* WARNING: This assumes the real output follows the virtual output in the
* device's DryBuffer.
*/
State->ExtraChannels = (Device->Hrtf || Device->Uhj_Encoder) ? 2 : 0;
// Calculate the modulation filter coefficient. Notice that the exponent
@ -666,16 +669,19 @@ static ALvoid UpdateMixedPanning(const ALCdevice *Device, const ALfloat *Reflect
ALfloat length;
ALuint i;
/* With HRTF, the normal output provides a panned reverb channel when a
* non-0-length vector is specified, while the real stereo output provides
* two other "direct" non-panned reverb channels.
/* With HRTF or UHJ, the normal output provides a panned reverb channel
* when a non-0-length vector is specified, while the real stereo output
* provides two other "direct" non-panned reverb channels.
*
* WARNING: This assumes the real output follows the virtual output in the
* device's DryBuffer.
*/
memset(State->Early.PanGain, 0, sizeof(State->Early.PanGain));
length = sqrtf(ReflectionsPan[0]*ReflectionsPan[0] + ReflectionsPan[1]*ReflectionsPan[1] + ReflectionsPan[2]*ReflectionsPan[2]);
if(!(length > FLT_EPSILON))
{
for(i = 0;i < 2;i++)
State->Early.PanGain[i&3][Device->NumChannels+i] = Gain * EarlyGain;
for(i = 0;i < Device->RealOut.NumChannels;i++)
State->Early.PanGain[i&3][Device->VirtOut.NumChannels+i] = Gain * EarlyGain;
}
else
{
@ -691,19 +697,19 @@ static ALvoid UpdateMixedPanning(const ALCdevice *Device, const ALfloat *Reflect
length = minf(length, 1.0f);
CalcDirectionCoeffs(pan, coeffs);
ComputePanningGains(Device->AmbiCoeffs, Device->NumChannels, coeffs, Gain, DirGains);
for(i = 0;i < Device->NumChannels;i++)
ComputePanningGains(Device->AmbiCoeffs, Device->VirtOut.NumChannels, coeffs, Gain, DirGains);
for(i = 0;i < Device->VirtOut.NumChannels;i++)
State->Early.PanGain[3][i] = DirGains[i] * EarlyGain * length;
for(i = 0;i < 2;i++)
State->Early.PanGain[i&3][Device->NumChannels+i] = Gain * EarlyGain * (1.0f-length);
for(i = 0;i < Device->RealOut.NumChannels;i++)
State->Early.PanGain[i&3][Device->VirtOut.NumChannels+i] = Gain * EarlyGain * (1.0f-length);
}
memset(State->Late.PanGain, 0, sizeof(State->Late.PanGain));
length = sqrtf(LateReverbPan[0]*LateReverbPan[0] + LateReverbPan[1]*LateReverbPan[1] + LateReverbPan[2]*LateReverbPan[2]);
if(!(length > FLT_EPSILON))
{
for(i = 0;i < 2;i++)
State->Late.PanGain[i&3][Device->NumChannels+i] = Gain * LateGain;
for(i = 0;i < Device->RealOut.NumChannels;i++)
State->Late.PanGain[i&3][Device->VirtOut.NumChannels+i] = Gain * LateGain;
}
else
{
@ -715,11 +721,11 @@ static ALvoid UpdateMixedPanning(const ALCdevice *Device, const ALfloat *Reflect
length = minf(length, 1.0f);
CalcDirectionCoeffs(pan, coeffs);
ComputePanningGains(Device->AmbiCoeffs, Device->NumChannels, coeffs, Gain, DirGains);
for(i = 0;i < Device->NumChannels;i++)
ComputePanningGains(Device->AmbiCoeffs, Device->VirtOut.NumChannels, coeffs, Gain, DirGains);
for(i = 0;i < Device->VirtOut.NumChannels;i++)
State->Late.PanGain[3][i] = DirGains[i] * LateGain * length;
for(i = 0;i < 2;i++)
State->Late.PanGain[i&3][Device->NumChannels+i] = Gain * LateGain * (1.0f-length);
for(i = 0;i < Device->RealOut.NumChannels;i++)
State->Late.PanGain[i&3][Device->VirtOut.NumChannels+i] = Gain * LateGain * (1.0f-length);
}
}

View File

@ -494,9 +494,20 @@ struct ALCdevice_struct
alignas(16) ALfloat ResampledData[BUFFERSIZE];
alignas(16) ALfloat FilteredData[BUFFERSIZE];
/* Dry path buffer mix. */
/* Dry path buffer mix (will be aliased by the virtual or real output). */
alignas(16) ALfloat (*DryBuffer)[BUFFERSIZE];
/* Virtual output, to be post-processed to the real output. */
struct {
ALfloat (*Buffer)[BUFFERSIZE];
ALuint NumChannels;
} VirtOut;
/* "Real" output, which will be written to the device buffer. */
struct {
ALfloat (*Buffer)[BUFFERSIZE];
ALuint NumChannels;
} RealOut;
/* 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