Use 2-channel UHJ for stereo output
This commit is contained in:
parent
67f086d1d4
commit
ac91083ceb
33
Alc/ALc.c
33
Alc/ALc.c
@ -36,6 +36,7 @@
|
||||
#include "alAuxEffectSlot.h"
|
||||
#include "alError.h"
|
||||
#include "bs2b.h"
|
||||
#include "uhjfilter.h"
|
||||
#include "alu.h"
|
||||
|
||||
#include "compat.h"
|
||||
@ -1846,6 +1847,12 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList)
|
||||
if((device->Flags&DEVICE_RUNNING))
|
||||
return ALC_NO_ERROR;
|
||||
|
||||
al_free(device->Uhj_Encoder);
|
||||
device->Uhj_Encoder = NULL;
|
||||
|
||||
al_free(device->Bs2b);
|
||||
device->Bs2b = NULL;
|
||||
|
||||
al_free(device->DryBuffer);
|
||||
device->DryBuffer = NULL;
|
||||
|
||||
@ -1971,9 +1978,6 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList)
|
||||
{
|
||||
if(hrtf_appreq == Hrtf_Enable)
|
||||
device->Hrtf_Status = ALC_HRTF_UNSUPPORTED_FORMAT_SOFT;
|
||||
|
||||
free(device->Bs2b);
|
||||
device->Bs2b = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -2067,8 +2071,6 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList)
|
||||
device->Hrtf_Mode = hrtf_mode;
|
||||
device->Hrtf_Status = hrtf_status;
|
||||
TRACE("HRTF enabled, \"%s\"\n", al_string_get_cstr(device->Hrtf_Name));
|
||||
free(device->Bs2b);
|
||||
device->Bs2b = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -2080,27 +2082,25 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList)
|
||||
ConfigValueInt(al_string_get_cstr(device->DeviceName), NULL, "cf_level", &bs2blevel);
|
||||
if(bs2blevel > 0 && bs2blevel <= 6)
|
||||
{
|
||||
if(!device->Bs2b)
|
||||
{
|
||||
device->Bs2b = calloc(1, sizeof(*device->Bs2b));
|
||||
bs2b_clear(device->Bs2b);
|
||||
}
|
||||
device->Bs2b = al_calloc(16, sizeof(*device->Bs2b));
|
||||
bs2b_set_params(device->Bs2b, bs2blevel, device->Frequency);
|
||||
TRACE("BS2B enabled\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
free(device->Bs2b);
|
||||
device->Bs2b = NULL;
|
||||
TRACE("BS2B disabled\n");
|
||||
}
|
||||
|
||||
device->Uhj_Encoder = al_calloc(16, sizeof(Uhj2Encoder));
|
||||
}
|
||||
}
|
||||
|
||||
aluInitPanning(device);
|
||||
|
||||
/* With HRTF, allocate two extra channels for the post-filter output. */
|
||||
size = sizeof(device->DryBuffer[0]) * (device->NumChannels + (device->Hrtf ? 2 : 0));
|
||||
size = device->NumChannels * sizeof(device->DryBuffer[0]);
|
||||
if(device->Hrtf || device->Uhj_Encoder)
|
||||
size += 2 * sizeof(device->DryBuffer[0]);
|
||||
device->DryBuffer = al_calloc(16, size);
|
||||
if(!device->DryBuffer)
|
||||
{
|
||||
@ -2235,9 +2235,12 @@ static ALCvoid FreeDevice(ALCdevice *device)
|
||||
AL_STRING_DEINIT(device->Hrtf_Name);
|
||||
FreeHrtfList(&device->Hrtf_List);
|
||||
|
||||
free(device->Bs2b);
|
||||
al_free(device->Bs2b);
|
||||
device->Bs2b = NULL;
|
||||
|
||||
al_free(device->Uhj_Encoder);
|
||||
device->Uhj_Encoder = NULL;
|
||||
|
||||
AL_STRING_DEINIT(device->DeviceName);
|
||||
|
||||
al_free(device->DryBuffer);
|
||||
@ -3336,6 +3339,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName)
|
||||
|
||||
device->Flags = 0;
|
||||
device->Bs2b = NULL;
|
||||
device->Uhj_Encoder = NULL;
|
||||
VECTOR_INIT(device->Hrtf_List);
|
||||
AL_STRING_INIT(device->Hrtf_Name);
|
||||
device->Hrtf_Mode = DisabledHrtf;
|
||||
@ -3782,6 +3786,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcLoopbackOpenDeviceSOFT(const ALCchar *deviceN
|
||||
VECTOR_INIT(device->Hrtf_List);
|
||||
AL_STRING_INIT(device->Hrtf_Name);
|
||||
device->Bs2b = NULL;
|
||||
device->Uhj_Encoder = NULL;
|
||||
device->Hrtf_Mode = DisabledHrtf;
|
||||
AL_STRING_INIT(device->DeviceName);
|
||||
device->DryBuffer = NULL;
|
||||
|
61
Alc/ALu.c
61
Alc/ALu.c
@ -34,6 +34,7 @@
|
||||
#include "alu.h"
|
||||
#include "bs2b.h"
|
||||
#include "hrtf.h"
|
||||
#include "uhjfilter.h"
|
||||
#include "static_assert.h"
|
||||
|
||||
#include "mixer_defs.h"
|
||||
@ -100,19 +101,18 @@ extern inline void aluMatrixdSet(aluMatrixd *matrix,
|
||||
ALdouble m30, ALdouble m31, ALdouble m32, ALdouble m33);
|
||||
|
||||
|
||||
/* NOTE: HRTF is set up a bit special in the device. By default, without HRTF,
|
||||
* the device's DryBuffer, NumChannels, ChannelName, and Channel fields
|
||||
* correspond to the output format, and the DryBuffer is then converted and
|
||||
* written to the backend's audio buffer.
|
||||
/* NOTE: HRTF and UHJ are set up a bit special in the device. Normally the
|
||||
* device's DryBuffer, NumChannels, ChannelName, and Channel fields correspond
|
||||
* to the output format, and the DryBuffer is then converted and written to the
|
||||
* backend's audio buffer.
|
||||
*
|
||||
* With HRTF, these fields correspond to a virtual format, and the actual
|
||||
* output is stored in DryBuffer[NumChannels] for the left channel and
|
||||
* With HRTF or UHJ, these fields correspond to a virtual format, and the
|
||||
* actual output is stored in DryBuffer[NumChannels] for the left channel and
|
||||
* DryBuffer[NumChannels+1] for the right. As a final output step,
|
||||
* the virtual channels will have HRTF applied and written to the actual
|
||||
* output. Things like effects and B-Format decoding will want to write to the
|
||||
* virtual channels so that they can be mixed with HRTF in full 3D.
|
||||
* the virtual channels will have HRTF filters or UHJ encoding applied and
|
||||
* written to the actual output.
|
||||
*
|
||||
* Sources that get mixed using HRTF directly (or that want to skip HRTF
|
||||
* Sources that get mixed using HRTF directly (or that want to skip HRTF or UHJ
|
||||
* completely) will need to offset the output buffer so that they skip the
|
||||
* virtual output and write to the actual output channels. This is the reason
|
||||
* you'll see
|
||||
@ -327,9 +327,6 @@ ALvoid CalcNonAttnSourceParams(ALvoice *voice, const ALsource *ALSource, const A
|
||||
}, StereoMap[2] = {
|
||||
{ FrontLeft, DEG2RAD(-30.0f), DEG2RAD(0.0f) },
|
||||
{ FrontRight, DEG2RAD( 30.0f), DEG2RAD(0.0f) }
|
||||
}, StereoWideMap[2] = {
|
||||
{ FrontLeft, DEG2RAD(-90.0f), DEG2RAD(0.0f) },
|
||||
{ FrontRight, DEG2RAD( 90.0f), DEG2RAD(0.0f) }
|
||||
}, RearMap[2] = {
|
||||
{ BackLeft, DEG2RAD(-150.0f), DEG2RAD(0.0f) },
|
||||
{ BackRight, DEG2RAD( 150.0f), DEG2RAD(0.0f) }
|
||||
@ -459,13 +456,7 @@ ALvoid CalcNonAttnSourceParams(ALvoice *voice, const ALsource *ALSource, const A
|
||||
break;
|
||||
|
||||
case FmtStereo:
|
||||
/* HACK: Place the stereo channels at +/-90 degrees when using non-
|
||||
* HRTF stereo output. This helps reduce the "monoization" caused
|
||||
* by them panning towards the center. */
|
||||
if(Device->FmtChans == DevFmtStereo && !Device->Hrtf)
|
||||
chans = StereoWideMap;
|
||||
else
|
||||
chans = StereoMap;
|
||||
chans = StereoMap;
|
||||
num_channels = 2;
|
||||
break;
|
||||
|
||||
@ -584,7 +575,7 @@ ALvoid CalcNonAttnSourceParams(ALvoice *voice, const ALsource *ALSource, const A
|
||||
|
||||
if(DirectChannels)
|
||||
{
|
||||
if(Device->Hrtf)
|
||||
if(Device->Hrtf || Device->Uhj_Encoder)
|
||||
{
|
||||
/* DirectChannels with HRTF enabled. Skip the virtual channels
|
||||
* and write FrontLeft and FrontRight inputs to the first and
|
||||
@ -1384,7 +1375,7 @@ ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size)
|
||||
SamplesToDo = minu(size, BUFFERSIZE);
|
||||
for(c = 0;c < OutChannels;c++)
|
||||
memset(OutBuffer[c], 0, SamplesToDo*sizeof(ALfloat));
|
||||
if(device->Hrtf)
|
||||
if(device->Hrtf || device->Uhj_Encoder)
|
||||
{
|
||||
/* Set OutBuffer/OutChannels to correspond to the actual output
|
||||
* with HRTF. Make sure to clear them too. */
|
||||
@ -1485,17 +1476,25 @@ ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size)
|
||||
}
|
||||
device->Hrtf_Offset += SamplesToDo;
|
||||
}
|
||||
else if(device->Bs2b)
|
||||
else
|
||||
{
|
||||
/* Apply binaural/crossfeed filter */
|
||||
for(i = 0;i < SamplesToDo;i++)
|
||||
if(device->Uhj_Encoder)
|
||||
{
|
||||
float samples[2];
|
||||
samples[0] = device->DryBuffer[0][i];
|
||||
samples[1] = device->DryBuffer[1][i];
|
||||
bs2b_cross_feed(device->Bs2b, samples);
|
||||
device->DryBuffer[0][i] = samples[0];
|
||||
device->DryBuffer[1][i] = samples[1];
|
||||
/* Encode to stereo-compatible 2-channel UHJ output. */
|
||||
EncodeUhj2(device->Uhj_Encoder, OutBuffer, device->DryBuffer, SamplesToDo);
|
||||
}
|
||||
if(device->Bs2b)
|
||||
{
|
||||
/* Apply binaural/crossfeed filter */
|
||||
for(i = 0;i < SamplesToDo;i++)
|
||||
{
|
||||
float samples[2];
|
||||
samples[0] = OutBuffer[0][i];
|
||||
samples[1] = OutBuffer[1][i];
|
||||
bs2b_cross_feed(device->Bs2b, samples);
|
||||
OutBuffer[0][i] = samples[0];
|
||||
OutBuffer[1][i] = samples[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -659,7 +659,7 @@ static ALvoid UpdateEchoLine(ALfloat echoTime, ALfloat decayTime, ALfloat diffus
|
||||
}
|
||||
|
||||
// Update the early and late 3D panning gains.
|
||||
static ALvoid UpdateHrtfPanning(const ALCdevice *Device, const ALfloat *ReflectionsPan, const ALfloat *LateReverbPan, ALfloat Gain, ALfloat EarlyGain, ALfloat LateGain, ALreverbState *State)
|
||||
static ALvoid UpdateMixedPanning(const ALCdevice *Device, const ALfloat *ReflectionsPan, const ALfloat *LateReverbPan, ALfloat Gain, ALfloat EarlyGain, ALfloat LateGain, ALreverbState *State)
|
||||
{
|
||||
ALfloat DirGains[MAX_OUTPUT_CHANNELS];
|
||||
ALfloat coeffs[MAX_AMBI_COEFFS];
|
||||
@ -925,11 +925,11 @@ static ALvoid ALreverbState_update(ALreverbState *State, const ALCdevice *Device
|
||||
|
||||
gain = props->Reverb.Gain * Slot->Gain * ReverbBoost;
|
||||
// Update early and late 3D panning.
|
||||
if(Device->Hrtf)
|
||||
UpdateHrtfPanning(Device, props->Reverb.ReflectionsPan,
|
||||
props->Reverb.LateReverbPan, gain,
|
||||
props->Reverb.ReflectionsGain,
|
||||
props->Reverb.LateReverbGain, State);
|
||||
if(Device->Hrtf || Device->Uhj_Encoder)
|
||||
UpdateMixedPanning(Device, props->Reverb.ReflectionsPan,
|
||||
props->Reverb.LateReverbPan, gain,
|
||||
props->Reverb.ReflectionsGain,
|
||||
props->Reverb.LateReverbGain, State);
|
||||
else if(Device->FmtChans == DevFmtBFormat3D)
|
||||
Update3DPanning(Device, props->Reverb.ReflectionsPan,
|
||||
props->Reverb.LateReverbPan, gain,
|
||||
|
@ -484,6 +484,10 @@ ALvoid aluInitPanning(ALCdevice *device)
|
||||
{ LowerFrontRight, { 0.176776695f, 0.072168784f, -0.072168784f, -0.072168784f } },
|
||||
{ LowerBackLeft, { 0.176776695f, -0.072168784f, 0.072168784f, -0.072168784f } },
|
||||
{ LowerBackRight, { 0.176776695f, -0.072168784f, -0.072168784f, -0.072168784f } },
|
||||
}, BFormat2D[3] = {
|
||||
{ BFormatW, { 1.0f, 0.0f, 0.0f, 0.0f } },
|
||||
{ BFormatX, { 0.0f, 1.0f, 0.0f, 0.0f } },
|
||||
{ BFormatY, { 0.0f, 0.0f, 1.0f, 0.0f } },
|
||||
}, BFormat3D[4] = {
|
||||
{ BFormatW, { 1.0f, 0.0f, 0.0f, 0.0f } },
|
||||
{ BFormatX, { 0.0f, 1.0f, 0.0f, 0.0f } },
|
||||
@ -493,6 +497,7 @@ ALvoid aluInitPanning(ALCdevice *device)
|
||||
const ChannelMap *chanmap = NULL;
|
||||
ALfloat ambiscale = 1.0f;
|
||||
size_t count = 0;
|
||||
ALuint i;
|
||||
|
||||
device->AmbiScale = 1.0f;
|
||||
memset(device->AmbiCoeffs, 0, sizeof(device->AmbiCoeffs));
|
||||
@ -514,7 +519,6 @@ ALvoid aluInitPanning(ALCdevice *device)
|
||||
{ LowerBackLeft, DEG2RAD(-135.0f), DEG2RAD(-45.0f) },
|
||||
{ LowerBackRight, DEG2RAD( 135.0f), DEG2RAD(-45.0f) },
|
||||
};
|
||||
ALuint i;
|
||||
|
||||
count = COUNTOF(Cube8Cfg);
|
||||
chanmap = Cube8Cfg;
|
||||
@ -536,6 +540,22 @@ ALvoid aluInitPanning(ALCdevice *device)
|
||||
}
|
||||
return;
|
||||
}
|
||||
if(device->Uhj_Encoder)
|
||||
{
|
||||
count = COUNTOF(BFormat2D);
|
||||
chanmap = BFormat2D;
|
||||
ambiscale = FIRST_ORDER_SCALE;
|
||||
|
||||
for(i = 0;i < count;i++)
|
||||
device->ChannelName[i] = chanmap[i].ChanName;
|
||||
for(;i < MAX_OUTPUT_CHANNELS;i++)
|
||||
device->ChannelName[i] = InvalidChannel;
|
||||
SetChannelMap(device->ChannelName, device->AmbiCoeffs, chanmap, count,
|
||||
&device->NumChannels, AL_TRUE);
|
||||
device->AmbiScale = ambiscale;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if(LoadChannelSetup(device))
|
||||
return;
|
||||
|
@ -470,6 +470,9 @@ struct ALCdevice_struct
|
||||
HrtfParams Hrtf_Params[MAX_OUTPUT_CHANNELS];
|
||||
ALuint Hrtf_Offset;
|
||||
|
||||
/* UHJ encoder state */
|
||||
struct Uhj2Encoder *Uhj_Encoder;
|
||||
|
||||
// Stereo-to-binaural filter
|
||||
struct bs2b *Bs2b;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user