Use a different method for HRTF mixing
This new method mixes sources normally into a 14-channel buffer with the channels placed all around the listener. HRTF is then applied to the channels given their positions and written to a 2-channel buffer, which gets written out to the device. This method has the benefit that HRTF processing becomes more scalable. The costly HRTF filters are applied to the 14-channel buffer after the mix is done, turning it into a post-process with a fixed overhead. Mixing sources is done with normal non-HRTF methods, so increasing the number of playing sources only incurs normal mixing costs. Another benefit is that it improves B-Format playback since the soundfield gets mixed into speakers covering all three dimensions, which then get filtered based on their locations. The main downside to this is that the spatial resolution of the HRTF dataset does not play a big role anymore. However, the hope is that with ambisonics- based panning, the perceptual position of panned sounds will still be good. It is also an option to increase the number of virtual channels for systems that can handle it, or maybe even decrease it for weaker systems.
This commit is contained in:
parent
38383671d7
commit
a27e5e1652
14
Alc/ALc.c
14
Alc/ALc.c
@ -1712,6 +1712,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList)
|
|||||||
enum DevFmtType oldType;
|
enum DevFmtType oldType;
|
||||||
ALCuint oldFreq;
|
ALCuint oldFreq;
|
||||||
FPUCtl oldMode;
|
FPUCtl oldMode;
|
||||||
|
size_t size;
|
||||||
|
|
||||||
// Check for attributes
|
// Check for attributes
|
||||||
if(device->Type == Loopback)
|
if(device->Type == Loopback)
|
||||||
@ -1885,6 +1886,9 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList)
|
|||||||
if((device->Flags&DEVICE_RUNNING))
|
if((device->Flags&DEVICE_RUNNING))
|
||||||
return ALC_NO_ERROR;
|
return ALC_NO_ERROR;
|
||||||
|
|
||||||
|
al_free(device->DryBuffer);
|
||||||
|
device->DryBuffer = NULL;
|
||||||
|
|
||||||
UpdateClockBase(device);
|
UpdateClockBase(device);
|
||||||
|
|
||||||
if(device->Type != Loopback)
|
if(device->Type != Loopback)
|
||||||
@ -1992,11 +1996,15 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList)
|
|||||||
|
|
||||||
aluInitPanning(device);
|
aluInitPanning(device);
|
||||||
|
|
||||||
al_free(device->DryBuffer);
|
/* With HRTF enabled, the channels are virtual and get positioned around
|
||||||
device->DryBuffer = al_calloc(16, sizeof(device->DryBuffer[0]) * device->NumChannels);
|
* the virtual listener. Two extra channels are allocated for the actual
|
||||||
|
* HRTF-filtered output.
|
||||||
|
*/
|
||||||
|
size = sizeof(device->DryBuffer[0]) * (device->NumChannels + (device->Hrtf ? 2 : 0));
|
||||||
|
device->DryBuffer = al_calloc(16, size);
|
||||||
if(!device->DryBuffer)
|
if(!device->DryBuffer)
|
||||||
{
|
{
|
||||||
ERR("Failed to allocate "SZFMT" bytes for mix buffer\n", sizeof(device->DryBuffer[0]) * device->NumChannels);
|
ERR("Failed to allocate "SZFMT" bytes for mix buffer\n", size);
|
||||||
return ALC_INVALID_DEVICE;
|
return ALC_INVALID_DEVICE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
163
Alc/ALu.c
163
Alc/ALu.c
@ -36,6 +36,8 @@
|
|||||||
#include "hrtf.h"
|
#include "hrtf.h"
|
||||||
#include "static_assert.h"
|
#include "static_assert.h"
|
||||||
|
|
||||||
|
#include "mixer_defs.h"
|
||||||
|
|
||||||
#include "backends/base.h"
|
#include "backends/base.h"
|
||||||
#include "midi/base.h"
|
#include "midi/base.h"
|
||||||
|
|
||||||
@ -83,6 +85,21 @@ extern inline ALfloat lerp(ALfloat val1, ALfloat val2, ALfloat mu);
|
|||||||
extern inline ALfloat cubic(ALfloat val0, ALfloat val1, ALfloat val2, ALfloat val3, ALfloat mu);
|
extern inline ALfloat cubic(ALfloat val0, ALfloat val1, ALfloat val2, ALfloat val3, ALfloat mu);
|
||||||
|
|
||||||
|
|
||||||
|
static inline HrtfMixerFunc SelectHrtfMixer(void)
|
||||||
|
{
|
||||||
|
#ifdef HAVE_SSE
|
||||||
|
if((CPUCapFlags&CPU_CAP_SSE))
|
||||||
|
return MixHrtf_SSE;
|
||||||
|
#endif
|
||||||
|
#ifdef HAVE_NEON
|
||||||
|
if((CPUCapFlags&CPU_CAP_NEON))
|
||||||
|
return MixHrtf_Neon;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return MixHrtf_C;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static inline void aluCrossproduct(const ALfloat *inVector1, const ALfloat *inVector2, ALfloat *outVector)
|
static inline void aluCrossproduct(const ALfloat *inVector1, const ALfloat *inVector2, ALfloat *outVector)
|
||||||
{
|
{
|
||||||
outVector[0] = inVector1[1]*inVector2[2] - inVector1[2]*inVector2[1];
|
outVector[0] = inVector1[1]*inVector2[2] - inVector1[2]*inVector2[1];
|
||||||
@ -492,37 +509,6 @@ ALvoid CalcNonAttnSourceParams(ALvoice *voice, const ALsource *ALSource, const A
|
|||||||
|
|
||||||
voice->IsHrtf = AL_FALSE;
|
voice->IsHrtf = AL_FALSE;
|
||||||
}
|
}
|
||||||
else if(Device->Hrtf)
|
|
||||||
{
|
|
||||||
for(c = 0;c < num_channels;c++)
|
|
||||||
{
|
|
||||||
if(chans[c].channel == LFE)
|
|
||||||
{
|
|
||||||
/* Skip LFE */
|
|
||||||
voice->Direct.Mix.Hrtf.Params[c].Delay[0] = 0;
|
|
||||||
voice->Direct.Mix.Hrtf.Params[c].Delay[1] = 0;
|
|
||||||
for(i = 0;i < HRIR_LENGTH;i++)
|
|
||||||
{
|
|
||||||
voice->Direct.Mix.Hrtf.Params[c].Coeffs[i][0] = 0.0f;
|
|
||||||
voice->Direct.Mix.Hrtf.Params[c].Coeffs[i][1] = 0.0f;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* Get the static HRIR coefficients and delays for this
|
|
||||||
* channel. */
|
|
||||||
GetLerpedHrtfCoeffs(Device->Hrtf,
|
|
||||||
chans[c].elevation, chans[c].angle, 1.0f, DryGain,
|
|
||||||
voice->Direct.Mix.Hrtf.Params[c].Coeffs,
|
|
||||||
voice->Direct.Mix.Hrtf.Params[c].Delay);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
voice->Direct.Counter = 0;
|
|
||||||
voice->Direct.Moving = AL_TRUE;
|
|
||||||
voice->Direct.Mix.Hrtf.IrSize = GetHrtfIrSize(Device->Hrtf);
|
|
||||||
|
|
||||||
voice->IsHrtf = AL_TRUE;
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
for(c = 0;c < num_channels;c++)
|
for(c = 0;c < num_channels;c++)
|
||||||
@ -929,70 +915,6 @@ ALvoid CalcSourceParams(ALvoice *voice, const ALsource *ALSource, const ALCconte
|
|||||||
BufferListItem = BufferListItem->next;
|
BufferListItem = BufferListItem->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(Device->Hrtf)
|
|
||||||
{
|
|
||||||
/* Use a binaural HRTF algorithm for stereo headphone playback */
|
|
||||||
ALfloat delta, ev = 0.0f, az = 0.0f;
|
|
||||||
ALfloat radius = ALSource->Radius;
|
|
||||||
ALfloat dirfact = 1.0f;
|
|
||||||
|
|
||||||
if(Distance > FLT_EPSILON)
|
|
||||||
{
|
|
||||||
ALfloat invlen = 1.0f/Distance;
|
|
||||||
Position[0] *= invlen;
|
|
||||||
Position[1] *= invlen;
|
|
||||||
Position[2] *= invlen;
|
|
||||||
|
|
||||||
/* Calculate elevation and azimuth only when the source is not at
|
|
||||||
* the listener. This prevents +0 and -0 Z from producing
|
|
||||||
* inconsistent panning. Also, clamp Y in case FP precision errors
|
|
||||||
* cause it to land outside of -1..+1. */
|
|
||||||
ev = asinf(clampf(Position[1], -1.0f, 1.0f));
|
|
||||||
az = atan2f(Position[0], -Position[2]*ZScale);
|
|
||||||
}
|
|
||||||
if(radius > Distance)
|
|
||||||
dirfact *= Distance / radius;
|
|
||||||
|
|
||||||
/* Check to see if the HRIR is already moving. */
|
|
||||||
if(voice->Direct.Moving)
|
|
||||||
{
|
|
||||||
/* Calculate the normalized HRTF transition factor (delta). */
|
|
||||||
delta = CalcHrtfDelta(voice->Direct.Mix.Hrtf.Gain, DryGain,
|
|
||||||
voice->Direct.Mix.Hrtf.Dir, Position);
|
|
||||||
/* If the delta is large enough, get the moving HRIR target
|
|
||||||
* coefficients, target delays, steppping values, and counter. */
|
|
||||||
if(delta > 0.001f)
|
|
||||||
{
|
|
||||||
ALuint counter = GetMovingHrtfCoeffs(Device->Hrtf,
|
|
||||||
ev, az, dirfact, DryGain, delta, voice->Direct.Counter,
|
|
||||||
voice->Direct.Mix.Hrtf.Params[0].Coeffs, voice->Direct.Mix.Hrtf.Params[0].Delay,
|
|
||||||
voice->Direct.Mix.Hrtf.Params[0].CoeffStep, voice->Direct.Mix.Hrtf.Params[0].DelayStep
|
|
||||||
);
|
|
||||||
voice->Direct.Counter = counter;
|
|
||||||
voice->Direct.Mix.Hrtf.Gain = DryGain;
|
|
||||||
voice->Direct.Mix.Hrtf.Dir[0] = Position[0];
|
|
||||||
voice->Direct.Mix.Hrtf.Dir[1] = Position[1];
|
|
||||||
voice->Direct.Mix.Hrtf.Dir[2] = Position[2];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* Get the initial (static) HRIR coefficients and delays. */
|
|
||||||
GetLerpedHrtfCoeffs(Device->Hrtf, ev, az, dirfact, DryGain,
|
|
||||||
voice->Direct.Mix.Hrtf.Params[0].Coeffs,
|
|
||||||
voice->Direct.Mix.Hrtf.Params[0].Delay);
|
|
||||||
voice->Direct.Counter = 0;
|
|
||||||
voice->Direct.Moving = AL_TRUE;
|
|
||||||
voice->Direct.Mix.Hrtf.Gain = DryGain;
|
|
||||||
voice->Direct.Mix.Hrtf.Dir[0] = Position[0];
|
|
||||||
voice->Direct.Mix.Hrtf.Dir[1] = Position[1];
|
|
||||||
voice->Direct.Mix.Hrtf.Dir[2] = Position[2];
|
|
||||||
}
|
|
||||||
voice->Direct.Mix.Hrtf.IrSize = GetHrtfIrSize(Device->Hrtf);
|
|
||||||
|
|
||||||
voice->IsHrtf = AL_TRUE;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
MixGains *gains = voice->Direct.Mix.Gains[0];
|
MixGains *gains = voice->Direct.Mix.Gains[0];
|
||||||
ALfloat radius = ALSource->Radius;
|
ALfloat radius = ALSource->Radius;
|
||||||
@ -1125,14 +1047,24 @@ ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size)
|
|||||||
|
|
||||||
while(size > 0)
|
while(size > 0)
|
||||||
{
|
{
|
||||||
|
ALuint outchanoffset = 0;
|
||||||
|
ALuint outchancount = device->NumChannels;
|
||||||
|
|
||||||
IncrementRef(&device->MixCount);
|
IncrementRef(&device->MixCount);
|
||||||
|
|
||||||
SamplesToDo = minu(size, BUFFERSIZE);
|
SamplesToDo = minu(size, BUFFERSIZE);
|
||||||
for(c = 0;c < device->NumChannels;c++)
|
for(c = 0;c < device->NumChannels;c++)
|
||||||
memset(device->DryBuffer[c], 0, SamplesToDo*sizeof(ALfloat));
|
memset(device->DryBuffer[c], 0, SamplesToDo*sizeof(ALfloat));
|
||||||
|
if(device->Hrtf)
|
||||||
|
{
|
||||||
|
outchanoffset = device->NumChannels;
|
||||||
|
outchancount = 2;
|
||||||
|
for(c = 0;c < outchancount;c++)
|
||||||
|
memset(device->DryBuffer[outchanoffset+c], 0, SamplesToDo*sizeof(ALfloat));
|
||||||
|
}
|
||||||
|
|
||||||
V0(device->Backend,lock)();
|
V0(device->Backend,lock)();
|
||||||
V(device->Synth,process)(SamplesToDo, device->DryBuffer);
|
V(device->Synth,process)(SamplesToDo, &device->DryBuffer[outchanoffset]);
|
||||||
|
|
||||||
ctx = ATOMIC_LOAD(&device->ContextList);
|
ctx = ATOMIC_LOAD(&device->ContextList);
|
||||||
while(ctx)
|
while(ctx)
|
||||||
@ -1212,7 +1144,16 @@ ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size)
|
|||||||
device->SamplesDone %= device->Frequency;
|
device->SamplesDone %= device->Frequency;
|
||||||
V0(device->Backend,unlock)();
|
V0(device->Backend,unlock)();
|
||||||
|
|
||||||
if(device->Bs2b)
|
if(device->Hrtf)
|
||||||
|
{
|
||||||
|
HrtfMixerFunc HrtfMix = SelectHrtfMixer();
|
||||||
|
ALuint irsize = GetHrtfIrSize(device->Hrtf);
|
||||||
|
for(c = 0;c < device->NumChannels;c++)
|
||||||
|
HrtfMix(&device->DryBuffer[outchanoffset], device->DryBuffer[c], device->Hrtf_Offset, irsize,
|
||||||
|
&device->Hrtf_Params[c], &device->Hrtf_State[c], SamplesToDo);
|
||||||
|
device->Hrtf_Offset += SamplesToDo;
|
||||||
|
}
|
||||||
|
else if(device->Bs2b)
|
||||||
{
|
{
|
||||||
/* Apply binaural/crossfeed filter */
|
/* Apply binaural/crossfeed filter */
|
||||||
for(i = 0;i < SamplesToDo;i++)
|
for(i = 0;i < SamplesToDo;i++)
|
||||||
@ -1231,32 +1172,32 @@ ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size)
|
|||||||
switch(device->FmtType)
|
switch(device->FmtType)
|
||||||
{
|
{
|
||||||
case DevFmtByte:
|
case DevFmtByte:
|
||||||
Write_ALbyte(device->DryBuffer, buffer, SamplesToDo, device->NumChannels);
|
Write_ALbyte(&device->DryBuffer[outchanoffset], buffer, SamplesToDo, outchancount);
|
||||||
buffer = (char*)buffer + SamplesToDo*device->NumChannels*sizeof(ALbyte);
|
buffer = (char*)buffer + SamplesToDo*outchancount*sizeof(ALbyte);
|
||||||
break;
|
break;
|
||||||
case DevFmtUByte:
|
case DevFmtUByte:
|
||||||
Write_ALubyte(device->DryBuffer, buffer, SamplesToDo, device->NumChannels);
|
Write_ALubyte(&device->DryBuffer[outchanoffset], buffer, SamplesToDo, outchancount);
|
||||||
buffer = (char*)buffer + SamplesToDo*device->NumChannels*sizeof(ALubyte);
|
buffer = (char*)buffer + SamplesToDo*outchancount*sizeof(ALubyte);
|
||||||
break;
|
break;
|
||||||
case DevFmtShort:
|
case DevFmtShort:
|
||||||
Write_ALshort(device->DryBuffer, buffer, SamplesToDo, device->NumChannels);
|
Write_ALshort(&device->DryBuffer[outchanoffset], buffer, SamplesToDo, outchancount);
|
||||||
buffer = (char*)buffer + SamplesToDo*device->NumChannels*sizeof(ALshort);
|
buffer = (char*)buffer + SamplesToDo*outchancount*sizeof(ALshort);
|
||||||
break;
|
break;
|
||||||
case DevFmtUShort:
|
case DevFmtUShort:
|
||||||
Write_ALushort(device->DryBuffer, buffer, SamplesToDo, device->NumChannels);
|
Write_ALushort(&device->DryBuffer[outchanoffset], buffer, SamplesToDo, outchancount);
|
||||||
buffer = (char*)buffer + SamplesToDo*device->NumChannels*sizeof(ALushort);
|
buffer = (char*)buffer + SamplesToDo*outchancount*sizeof(ALushort);
|
||||||
break;
|
break;
|
||||||
case DevFmtInt:
|
case DevFmtInt:
|
||||||
Write_ALint(device->DryBuffer, buffer, SamplesToDo, device->NumChannels);
|
Write_ALint(&device->DryBuffer[outchanoffset], buffer, SamplesToDo, outchancount);
|
||||||
buffer = (char*)buffer + SamplesToDo*device->NumChannels*sizeof(ALint);
|
buffer = (char*)buffer + SamplesToDo*outchancount*sizeof(ALint);
|
||||||
break;
|
break;
|
||||||
case DevFmtUInt:
|
case DevFmtUInt:
|
||||||
Write_ALuint(device->DryBuffer, buffer, SamplesToDo, device->NumChannels);
|
Write_ALuint(&device->DryBuffer[outchanoffset], buffer, SamplesToDo, outchancount);
|
||||||
buffer = (char*)buffer + SamplesToDo*device->NumChannels*sizeof(ALuint);
|
buffer = (char*)buffer + SamplesToDo*outchancount*sizeof(ALuint);
|
||||||
break;
|
break;
|
||||||
case DevFmtFloat:
|
case DevFmtFloat:
|
||||||
Write_ALfloat(device->DryBuffer, buffer, SamplesToDo, device->NumChannels);
|
Write_ALfloat(&device->DryBuffer[outchanoffset], buffer, SamplesToDo, outchancount);
|
||||||
buffer = (char*)buffer + SamplesToDo*device->NumChannels*sizeof(ALfloat);
|
buffer = (char*)buffer + SamplesToDo*outchancount*sizeof(ALfloat);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
220
Alc/hrtf.c
220
Alc/hrtf.c
@ -58,10 +58,6 @@ struct Hrtf {
|
|||||||
static const ALchar magicMarker00[8] = "MinPHR00";
|
static const ALchar magicMarker00[8] = "MinPHR00";
|
||||||
static const ALchar magicMarker01[8] = "MinPHR01";
|
static const ALchar magicMarker01[8] = "MinPHR01";
|
||||||
|
|
||||||
/* First value for pass-through coefficients (remaining are 0), used for omni-
|
|
||||||
* directional sounds. */
|
|
||||||
static const ALfloat PassthruCoeff = 32767.0f * 0.707106781187f/*sqrt(0.5)*/;
|
|
||||||
|
|
||||||
static struct Hrtf *LoadedHrtfs = NULL;
|
static struct Hrtf *LoadedHrtfs = NULL;
|
||||||
|
|
||||||
/* Calculate the elevation indices given the polar elevation in radians.
|
/* Calculate the elevation indices given the polar elevation in radians.
|
||||||
@ -88,45 +84,12 @@ static void CalcAzIndices(ALuint azcount, ALfloat az, ALuint *azidx, ALfloat *az
|
|||||||
*azmu = az - floorf(az);
|
*azmu = az - floorf(az);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Calculates the normalized HRTF transition factor (delta) from the changes
|
|
||||||
* in gain and listener to source angle between updates. The result is a
|
|
||||||
* normalized delta factor that can be used to calculate moving HRIR stepping
|
|
||||||
* values.
|
|
||||||
*/
|
|
||||||
ALfloat CalcHrtfDelta(ALfloat oldGain, ALfloat newGain, const ALfloat olddir[3], const ALfloat newdir[3])
|
|
||||||
{
|
|
||||||
ALfloat gainChange, angleChange, change;
|
|
||||||
|
|
||||||
// Calculate the normalized dB gain change.
|
|
||||||
newGain = maxf(newGain, 0.0001f);
|
|
||||||
oldGain = maxf(oldGain, 0.0001f);
|
|
||||||
gainChange = fabsf(log10f(newGain / oldGain) / log10f(0.0001f));
|
|
||||||
|
|
||||||
// Calculate the angle change only when there is enough gain to notice it.
|
|
||||||
angleChange = 0.0f;
|
|
||||||
if(gainChange > 0.0001f || newGain > 0.0001f)
|
|
||||||
{
|
|
||||||
// No angle change when the directions are equal or degenerate (when
|
|
||||||
// both have zero length).
|
|
||||||
if(newdir[0] != olddir[0] || newdir[1] != olddir[1] || newdir[2] != olddir[2])
|
|
||||||
{
|
|
||||||
ALfloat dotp = olddir[0]*newdir[0] + olddir[1]*newdir[1] + olddir[2]*newdir[2];
|
|
||||||
angleChange = acosf(clampf(dotp, -1.0f, 1.0f)) / F_PI;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use the largest of the two changes for the delta factor, and apply a
|
|
||||||
// significance shaping function to it.
|
|
||||||
change = maxf(angleChange * 25.0f, gainChange) * 2.0f;
|
|
||||||
return minf(change, 1.0f);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Calculates static HRIR coefficients and delays for the given polar
|
/* Calculates static HRIR coefficients and delays for the given polar
|
||||||
* elevation and azimuth in radians. Linear interpolation is used to
|
* elevation and azimuth in radians. Linear interpolation is used to
|
||||||
* increase the apparent resolution of the HRIR data set. The coefficients
|
* increase the apparent resolution of the HRIR data set. The coefficients
|
||||||
* are also normalized and attenuated by the specified gain.
|
* are also normalized and attenuated by the specified gain.
|
||||||
*/
|
*/
|
||||||
void GetLerpedHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azimuth, ALfloat dirfact, ALfloat gain, ALfloat (*coeffs)[2], ALuint *delays)
|
void GetLerpedHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azimuth, ALfloat (*coeffs)[2], ALuint *delays)
|
||||||
{
|
{
|
||||||
ALuint evidx[2], lidx[4], ridx[4];
|
ALuint evidx[2], lidx[4], ridx[4];
|
||||||
ALfloat mu[3], blend[4];
|
ALfloat mu[3], blend[4];
|
||||||
@ -158,12 +121,12 @@ void GetLerpedHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azi
|
|||||||
blend[3] = ( mu[1]) * ( mu[2]);
|
blend[3] = ( mu[1]) * ( mu[2]);
|
||||||
|
|
||||||
/* Calculate the HRIR delays using linear interpolation. */
|
/* Calculate the HRIR delays using linear interpolation. */
|
||||||
delays[0] = fastf2u((Hrtf->delays[lidx[0]]*blend[0] + Hrtf->delays[lidx[1]]*blend[1] +
|
delays[0] = fastf2u(Hrtf->delays[lidx[0]]*blend[0] + Hrtf->delays[lidx[1]]*blend[1] +
|
||||||
Hrtf->delays[lidx[2]]*blend[2] + Hrtf->delays[lidx[3]]*blend[3]) *
|
Hrtf->delays[lidx[2]]*blend[2] + Hrtf->delays[lidx[3]]*blend[3] +
|
||||||
dirfact + 0.5f) << HRTFDELAY_BITS;
|
0.5f);
|
||||||
delays[1] = fastf2u((Hrtf->delays[ridx[0]]*blend[0] + Hrtf->delays[ridx[1]]*blend[1] +
|
delays[1] = fastf2u(Hrtf->delays[ridx[0]]*blend[0] + Hrtf->delays[ridx[1]]*blend[1] +
|
||||||
Hrtf->delays[ridx[2]]*blend[2] + Hrtf->delays[ridx[3]]*blend[3]) *
|
Hrtf->delays[ridx[2]]*blend[2] + Hrtf->delays[ridx[3]]*blend[3] +
|
||||||
dirfact + 0.5f) << HRTFDELAY_BITS;
|
0.5f);
|
||||||
|
|
||||||
/* Calculate the sample offsets for the HRIR indices. */
|
/* Calculate the sample offsets for the HRIR indices. */
|
||||||
lidx[0] *= Hrtf->irSize;
|
lidx[0] *= Hrtf->irSize;
|
||||||
@ -175,183 +138,22 @@ void GetLerpedHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azi
|
|||||||
ridx[2] *= Hrtf->irSize;
|
ridx[2] *= Hrtf->irSize;
|
||||||
ridx[3] *= Hrtf->irSize;
|
ridx[3] *= Hrtf->irSize;
|
||||||
|
|
||||||
/* Calculate the normalized and attenuated HRIR coefficients using linear
|
|
||||||
* interpolation when there is enough gain to warrant it. Zero the
|
|
||||||
* coefficients if gain is too low.
|
|
||||||
*/
|
|
||||||
if(gain > 0.0001f)
|
|
||||||
{
|
|
||||||
ALfloat c;
|
|
||||||
|
|
||||||
gain *= 1.0f/32767.0f;
|
|
||||||
|
|
||||||
i = 0;
|
|
||||||
c = (Hrtf->coeffs[lidx[0]+i]*blend[0] + Hrtf->coeffs[lidx[1]+i]*blend[1] +
|
|
||||||
Hrtf->coeffs[lidx[2]+i]*blend[2] + Hrtf->coeffs[lidx[3]+i]*blend[3]);
|
|
||||||
coeffs[i][0] = lerp(PassthruCoeff, c, dirfact) * gain;
|
|
||||||
c = (Hrtf->coeffs[ridx[0]+i]*blend[0] + Hrtf->coeffs[ridx[1]+i]*blend[1] +
|
|
||||||
Hrtf->coeffs[ridx[2]+i]*blend[2] + Hrtf->coeffs[ridx[3]+i]*blend[3]);
|
|
||||||
coeffs[i][1] = lerp(PassthruCoeff, c, dirfact) * gain;
|
|
||||||
|
|
||||||
for(i = 1;i < Hrtf->irSize;i++)
|
|
||||||
{
|
|
||||||
c = (Hrtf->coeffs[lidx[0]+i]*blend[0] + Hrtf->coeffs[lidx[1]+i]*blend[1] +
|
|
||||||
Hrtf->coeffs[lidx[2]+i]*blend[2] + Hrtf->coeffs[lidx[3]+i]*blend[3]);
|
|
||||||
coeffs[i][0] = lerp(0.0f, c, dirfact) * gain;
|
|
||||||
c = (Hrtf->coeffs[ridx[0]+i]*blend[0] + Hrtf->coeffs[ridx[1]+i]*blend[1] +
|
|
||||||
Hrtf->coeffs[ridx[2]+i]*blend[2] + Hrtf->coeffs[ridx[3]+i]*blend[3]);
|
|
||||||
coeffs[i][1] = lerp(0.0f, c, dirfact) * gain;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for(i = 0;i < Hrtf->irSize;i++)
|
for(i = 0;i < Hrtf->irSize;i++)
|
||||||
{
|
|
||||||
coeffs[i][0] = 0.0f;
|
|
||||||
coeffs[i][1] = 0.0f;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Calculates the moving HRIR target coefficients, target delays, and
|
|
||||||
* stepping values for the given polar elevation and azimuth in radians.
|
|
||||||
* Linear interpolation is used to increase the apparent resolution of the
|
|
||||||
* HRIR data set. The coefficients are also normalized and attenuated by the
|
|
||||||
* specified gain. Stepping resolution and count is determined using the
|
|
||||||
* given delta factor between 0.0 and 1.0.
|
|
||||||
*/
|
|
||||||
ALuint GetMovingHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azimuth, ALfloat dirfact, ALfloat gain, ALfloat delta, ALint counter, ALfloat (*coeffs)[2], ALuint *delays, ALfloat (*coeffStep)[2], ALint *delayStep)
|
|
||||||
{
|
|
||||||
ALuint evidx[2], lidx[4], ridx[4];
|
|
||||||
ALfloat mu[3], blend[4];
|
|
||||||
ALfloat left, right;
|
|
||||||
ALfloat step;
|
|
||||||
ALuint i;
|
|
||||||
|
|
||||||
/* Claculate elevation indices and interpolation factor. */
|
|
||||||
CalcEvIndices(Hrtf->evCount, elevation, evidx, &mu[2]);
|
|
||||||
|
|
||||||
for(i = 0;i < 2;i++)
|
|
||||||
{
|
|
||||||
ALuint azcount = Hrtf->azCount[evidx[i]];
|
|
||||||
ALuint evoffset = Hrtf->evOffset[evidx[i]];
|
|
||||||
ALuint azidx[2];
|
|
||||||
|
|
||||||
/* Calculate azimuth indices and interpolation factor for this elevation. */
|
|
||||||
CalcAzIndices(azcount, azimuth, azidx, &mu[i]);
|
|
||||||
|
|
||||||
/* Calculate a set of linear HRIR indices for left and right channels. */
|
|
||||||
lidx[i*2 + 0] = evoffset + azidx[0];
|
|
||||||
lidx[i*2 + 1] = evoffset + azidx[1];
|
|
||||||
ridx[i*2 + 0] = evoffset + ((azcount-azidx[0]) % azcount);
|
|
||||||
ridx[i*2 + 1] = evoffset + ((azcount-azidx[1]) % azcount);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Calculate the stepping parameters.
|
|
||||||
delta = maxf(floorf(delta*(Hrtf->sampleRate*0.015f) + 0.5f), 1.0f);
|
|
||||||
step = 1.0f / delta;
|
|
||||||
|
|
||||||
/* Calculate 4 blending weights for 2D bilinear interpolation. */
|
|
||||||
blend[0] = (1.0f-mu[0]) * (1.0f-mu[2]);
|
|
||||||
blend[1] = ( mu[0]) * (1.0f-mu[2]);
|
|
||||||
blend[2] = (1.0f-mu[1]) * ( mu[2]);
|
|
||||||
blend[3] = ( mu[1]) * ( mu[2]);
|
|
||||||
|
|
||||||
/* Calculate the HRIR delays using linear interpolation. Then calculate
|
|
||||||
* the delay stepping values using the target and previous running
|
|
||||||
* delays.
|
|
||||||
*/
|
|
||||||
left = (ALfloat)(delays[0] - (delayStep[0] * counter));
|
|
||||||
right = (ALfloat)(delays[1] - (delayStep[1] * counter));
|
|
||||||
|
|
||||||
delays[0] = fastf2u((Hrtf->delays[lidx[0]]*blend[0] + Hrtf->delays[lidx[1]]*blend[1] +
|
|
||||||
Hrtf->delays[lidx[2]]*blend[2] + Hrtf->delays[lidx[3]]*blend[3]) *
|
|
||||||
dirfact + 0.5f) << HRTFDELAY_BITS;
|
|
||||||
delays[1] = fastf2u((Hrtf->delays[ridx[0]]*blend[0] + Hrtf->delays[ridx[1]]*blend[1] +
|
|
||||||
Hrtf->delays[ridx[2]]*blend[2] + Hrtf->delays[ridx[3]]*blend[3]) *
|
|
||||||
dirfact + 0.5f) << HRTFDELAY_BITS;
|
|
||||||
|
|
||||||
delayStep[0] = fastf2i(step * (delays[0] - left));
|
|
||||||
delayStep[1] = fastf2i(step * (delays[1] - right));
|
|
||||||
|
|
||||||
/* Calculate the sample offsets for the HRIR indices. */
|
|
||||||
lidx[0] *= Hrtf->irSize;
|
|
||||||
lidx[1] *= Hrtf->irSize;
|
|
||||||
lidx[2] *= Hrtf->irSize;
|
|
||||||
lidx[3] *= Hrtf->irSize;
|
|
||||||
ridx[0] *= Hrtf->irSize;
|
|
||||||
ridx[1] *= Hrtf->irSize;
|
|
||||||
ridx[2] *= Hrtf->irSize;
|
|
||||||
ridx[3] *= Hrtf->irSize;
|
|
||||||
|
|
||||||
/* Calculate the normalized and attenuated target HRIR coefficients using
|
|
||||||
* linear interpolation when there is enough gain to warrant it. Zero
|
|
||||||
* the target coefficients if gain is too low. Then calculate the
|
|
||||||
* coefficient stepping values using the target and previous running
|
|
||||||
* coefficients.
|
|
||||||
*/
|
|
||||||
if(gain > 0.0001f)
|
|
||||||
{
|
{
|
||||||
ALfloat c;
|
ALfloat c;
|
||||||
|
|
||||||
gain *= 1.0f/32767.0f;
|
|
||||||
|
|
||||||
i = 0;
|
|
||||||
left = coeffs[i][0] - (coeffStep[i][0] * counter);
|
|
||||||
right = coeffs[i][1] - (coeffStep[i][1] * counter);
|
|
||||||
|
|
||||||
c = (Hrtf->coeffs[lidx[0]+i]*blend[0] + Hrtf->coeffs[lidx[1]+i]*blend[1] +
|
c = (Hrtf->coeffs[lidx[0]+i]*blend[0] + Hrtf->coeffs[lidx[1]+i]*blend[1] +
|
||||||
Hrtf->coeffs[lidx[2]+i]*blend[2] + Hrtf->coeffs[lidx[3]+i]*blend[3]);
|
Hrtf->coeffs[lidx[2]+i]*blend[2] + Hrtf->coeffs[lidx[3]+i]*blend[3]);
|
||||||
coeffs[i][0] = lerp(PassthruCoeff, c, dirfact) * gain;
|
coeffs[i][0] = c * (1.0f/32767.0f);
|
||||||
c = (Hrtf->coeffs[ridx[0]+i]*blend[0] + Hrtf->coeffs[ridx[1]+i]*blend[1] +
|
c = (Hrtf->coeffs[ridx[0]+i]*blend[0] + Hrtf->coeffs[ridx[1]+i]*blend[1] +
|
||||||
Hrtf->coeffs[ridx[2]+i]*blend[2] + Hrtf->coeffs[ridx[3]+i]*blend[3]);
|
Hrtf->coeffs[ridx[2]+i]*blend[2] + Hrtf->coeffs[ridx[3]+i]*blend[3]);
|
||||||
coeffs[i][1] = lerp(PassthruCoeff, c, dirfact) * gain;
|
coeffs[i][1] = c * (1.0f/32767.0f);
|
||||||
|
|
||||||
coeffStep[i][0] = step * (coeffs[i][0] - left);
|
|
||||||
coeffStep[i][1] = step * (coeffs[i][1] - right);
|
|
||||||
|
|
||||||
for(i = 1;i < Hrtf->irSize;i++)
|
|
||||||
{
|
|
||||||
left = coeffs[i][0] - (coeffStep[i][0] * counter);
|
|
||||||
right = coeffs[i][1] - (coeffStep[i][1] * counter);
|
|
||||||
|
|
||||||
c = (Hrtf->coeffs[lidx[0]+i]*blend[0] + Hrtf->coeffs[lidx[1]+i]*blend[1] +
|
|
||||||
Hrtf->coeffs[lidx[2]+i]*blend[2] + Hrtf->coeffs[lidx[3]+i]*blend[3]);
|
|
||||||
coeffs[i][0] = lerp(0.0f, c, dirfact) * gain;
|
|
||||||
c = (Hrtf->coeffs[ridx[0]+i]*blend[0] + Hrtf->coeffs[ridx[1]+i]*blend[1] +
|
|
||||||
Hrtf->coeffs[ridx[2]+i]*blend[2] + Hrtf->coeffs[ridx[3]+i]*blend[3]);
|
|
||||||
coeffs[i][1] = lerp(0.0f, c, dirfact) * gain;
|
|
||||||
|
|
||||||
coeffStep[i][0] = step * (coeffs[i][0] - left);
|
|
||||||
coeffStep[i][1] = step * (coeffs[i][1] - right);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for(i = 0;i < Hrtf->irSize;i++)
|
|
||||||
{
|
|
||||||
left = coeffs[i][0] - (coeffStep[i][0] * counter);
|
|
||||||
right = coeffs[i][1] - (coeffStep[i][1] * counter);
|
|
||||||
|
|
||||||
coeffs[i][0] = 0.0f;
|
|
||||||
coeffs[i][1] = 0.0f;
|
|
||||||
|
|
||||||
coeffStep[i][0] = step * -left;
|
|
||||||
coeffStep[i][1] = step * -right;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* The stepping count is the number of samples necessary for the HRIR to
|
|
||||||
* complete its transition. The mixer will only apply stepping for this
|
|
||||||
* many samples.
|
|
||||||
*/
|
|
||||||
return fastf2u(delta);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static struct Hrtf *LoadHrtf00(FILE *f, ALuint deviceRate)
|
static struct Hrtf *LoadHrtf00(FILE *f, ALuint deviceRate)
|
||||||
{
|
{
|
||||||
const ALubyte maxDelay = SRC_HISTORY_LENGTH-1;
|
const ALubyte maxDelay = HRTF_HISTORY_LENGTH-1;
|
||||||
struct Hrtf *Hrtf = NULL;
|
struct Hrtf *Hrtf = NULL;
|
||||||
ALboolean failed = AL_FALSE;
|
ALboolean failed = AL_FALSE;
|
||||||
ALuint rate = 0, irCount = 0;
|
ALuint rate = 0, irCount = 0;
|
||||||
@ -518,7 +320,7 @@ static struct Hrtf *LoadHrtf00(FILE *f, ALuint deviceRate)
|
|||||||
|
|
||||||
static struct Hrtf *LoadHrtf01(FILE *f, ALuint deviceRate)
|
static struct Hrtf *LoadHrtf01(FILE *f, ALuint deviceRate)
|
||||||
{
|
{
|
||||||
const ALubyte maxDelay = SRC_HISTORY_LENGTH-1;
|
const ALubyte maxDelay = HRTF_HISTORY_LENGTH-1;
|
||||||
struct Hrtf *Hrtf = NULL;
|
struct Hrtf *Hrtf = NULL;
|
||||||
ALboolean failed = AL_FALSE;
|
ALboolean failed = AL_FALSE;
|
||||||
ALuint rate = 0, irCount = 0;
|
ALuint rate = 0, irCount = 0;
|
||||||
|
@ -21,8 +21,6 @@ ALCboolean FindHrtfFormat(enum DevFmtChannels *chans, ALCuint *srate);
|
|||||||
void FreeHrtfs(void);
|
void FreeHrtfs(void);
|
||||||
|
|
||||||
ALuint GetHrtfIrSize(const struct Hrtf *Hrtf);
|
ALuint GetHrtfIrSize(const struct Hrtf *Hrtf);
|
||||||
ALfloat CalcHrtfDelta(ALfloat oldGain, ALfloat newGain, const ALfloat olddir[3], const ALfloat newdir[3]);
|
void GetLerpedHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azimuth, ALfloat (*coeffs)[2], ALuint *delays);
|
||||||
void GetLerpedHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azimuth, ALfloat dirfact, ALfloat gain, ALfloat (*coeffs)[2], ALuint *delays);
|
|
||||||
ALuint GetMovingHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azimuth, ALfloat dirfact, ALfloat gain, ALfloat delta, ALint counter, ALfloat (*coeffs)[2], ALuint *delays, ALfloat (*coeffStep)[2], ALint *delayStep);
|
|
||||||
|
|
||||||
#endif /* ALC_HRTF_H */
|
#endif /* ALC_HRTF_H */
|
||||||
|
@ -853,8 +853,8 @@ static void FSynth_process(FSynth *self, ALuint SamplesToDo, ALfloat (*restrict
|
|||||||
return;
|
return;
|
||||||
if(state != AL_PLAYING)
|
if(state != AL_PLAYING)
|
||||||
{
|
{
|
||||||
fluid_synth_write_float(self->Synth, SamplesToDo, DryBuffer[FrontLeft], 0, 1,
|
fluid_synth_write_float(self->Synth, SamplesToDo, DryBuffer[0], 0, 1,
|
||||||
DryBuffer[FrontRight], 0, 1);
|
DryBuffer[1], 0, 1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -882,8 +882,8 @@ static void FSynth_process(FSynth *self, ALuint SamplesToDo, ALfloat (*restrict
|
|||||||
if(tonext > 0)
|
if(tonext > 0)
|
||||||
{
|
{
|
||||||
ALuint todo = minu(tonext, SamplesToDo-total);
|
ALuint todo = minu(tonext, SamplesToDo-total);
|
||||||
fluid_synth_write_float(self->Synth, todo, DryBuffer[FrontLeft], total, 1,
|
fluid_synth_write_float(self->Synth, todo, DryBuffer[0], total, 1,
|
||||||
DryBuffer[FrontRight], total, 1);
|
DryBuffer[1], total, 1);
|
||||||
total += todo;
|
total += todo;
|
||||||
tonext -= todo;
|
tonext -= todo;
|
||||||
}
|
}
|
||||||
|
21
Alc/mixer.c
21
Alc/mixer.c
@ -41,20 +41,6 @@
|
|||||||
extern inline void InitiatePositionArrays(ALuint frac, ALuint increment, ALuint *frac_arr, ALuint *pos_arr, ALuint size);
|
extern inline void InitiatePositionArrays(ALuint frac, ALuint increment, ALuint *frac_arr, ALuint *pos_arr, ALuint size);
|
||||||
|
|
||||||
|
|
||||||
static inline HrtfMixerFunc SelectHrtfMixer(void)
|
|
||||||
{
|
|
||||||
#ifdef HAVE_SSE
|
|
||||||
if((CPUCapFlags&CPU_CAP_SSE))
|
|
||||||
return MixHrtf_SSE;
|
|
||||||
#endif
|
|
||||||
#ifdef HAVE_NEON
|
|
||||||
if((CPUCapFlags&CPU_CAP_NEON))
|
|
||||||
return MixHrtf_Neon;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return MixHrtf_C;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline MixerFunc SelectMixer(void)
|
static inline MixerFunc SelectMixer(void)
|
||||||
{
|
{
|
||||||
#ifdef HAVE_SSE
|
#ifdef HAVE_SSE
|
||||||
@ -179,7 +165,6 @@ static const ALfloat *DoFilters(ALfilterState *lpfilter, ALfilterState *hpfilter
|
|||||||
ALvoid MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALuint SamplesToDo)
|
ALvoid MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALuint SamplesToDo)
|
||||||
{
|
{
|
||||||
MixerFunc Mix;
|
MixerFunc Mix;
|
||||||
HrtfMixerFunc HrtfMix;
|
|
||||||
ResamplerFunc Resample;
|
ResamplerFunc Resample;
|
||||||
ALbufferlistitem *BufferListItem;
|
ALbufferlistitem *BufferListItem;
|
||||||
ALuint DataPosInt, DataPosFrac;
|
ALuint DataPosInt, DataPosFrac;
|
||||||
@ -218,7 +203,6 @@ ALvoid MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALuint Sam
|
|||||||
}
|
}
|
||||||
|
|
||||||
Mix = SelectMixer();
|
Mix = SelectMixer();
|
||||||
HrtfMix = SelectHrtfMixer();
|
|
||||||
Resample = ((increment == FRACTIONONE && DataPosFrac == 0) ?
|
Resample = ((increment == FRACTIONONE && DataPosFrac == 0) ?
|
||||||
Resample_copy32_C : SelectResampler(Resampler));
|
Resample_copy32_C : SelectResampler(Resampler));
|
||||||
|
|
||||||
@ -431,13 +415,8 @@ ALvoid MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALuint Sam
|
|||||||
Device->FilteredData, ResampledData, DstBufferSize,
|
Device->FilteredData, ResampledData, DstBufferSize,
|
||||||
parms->Filters[chan].ActiveType
|
parms->Filters[chan].ActiveType
|
||||||
);
|
);
|
||||||
if(!voice->IsHrtf)
|
|
||||||
Mix(samples, Device->NumChannels, parms->OutBuffer, parms->Mix.Gains[chan],
|
Mix(samples, Device->NumChannels, parms->OutBuffer, parms->Mix.Gains[chan],
|
||||||
parms->Counter, OutPos, DstBufferSize);
|
parms->Counter, OutPos, DstBufferSize);
|
||||||
else
|
|
||||||
HrtfMix(parms->OutBuffer, samples, parms->Counter, voice->Offset,
|
|
||||||
OutPos, parms->Mix.Hrtf.IrSize, &parms->Mix.Hrtf.Params[chan],
|
|
||||||
&parms->Mix.Hrtf.State[chan], DstBufferSize);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Only the first channel for B-Format buffers (W channel) goes to
|
/* Only the first channel for B-Format buffers (W channel) goes to
|
||||||
|
@ -59,23 +59,6 @@ void ALfilterState_processC(ALfilterState *filter, ALfloat *restrict dst, const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static inline void ApplyCoeffsStep(ALuint Offset, ALfloat (*restrict Values)[2],
|
|
||||||
const ALuint IrSize,
|
|
||||||
ALfloat (*restrict Coeffs)[2],
|
|
||||||
const ALfloat (*restrict CoeffStep)[2],
|
|
||||||
ALfloat left, ALfloat right)
|
|
||||||
{
|
|
||||||
ALuint c;
|
|
||||||
for(c = 0;c < IrSize;c++)
|
|
||||||
{
|
|
||||||
const ALuint off = (Offset+c)&HRIR_MASK;
|
|
||||||
Values[off][0] += Coeffs[c][0] * left;
|
|
||||||
Values[off][1] += Coeffs[c][1] * right;
|
|
||||||
Coeffs[c][0] += CoeffStep[c][0];
|
|
||||||
Coeffs[c][1] += CoeffStep[c][1];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void ApplyCoeffs(ALuint Offset, ALfloat (*restrict Values)[2],
|
static inline void ApplyCoeffs(ALuint Offset, ALfloat (*restrict Values)[2],
|
||||||
const ALuint IrSize,
|
const ALuint IrSize,
|
||||||
ALfloat (*restrict Coeffs)[2],
|
ALfloat (*restrict Coeffs)[2],
|
||||||
|
@ -20,17 +20,15 @@ const ALfloat *Resample_cubic32_C(const ALfloat *src, ALuint frac, ALuint increm
|
|||||||
|
|
||||||
/* C mixers */
|
/* C mixers */
|
||||||
void MixHrtf_C(ALfloat (*restrict OutBuffer)[BUFFERSIZE], const ALfloat *data,
|
void MixHrtf_C(ALfloat (*restrict OutBuffer)[BUFFERSIZE], const ALfloat *data,
|
||||||
ALuint Counter, ALuint Offset, ALuint OutPos, const ALuint IrSize,
|
ALuint Offset, const ALuint IrSize, const struct HrtfParams *hrtfparams,
|
||||||
const struct HrtfParams *hrtfparams, struct HrtfState *hrtfstate,
|
struct HrtfState *hrtfstate, ALuint BufferSize);
|
||||||
ALuint BufferSize);
|
|
||||||
void Mix_C(const ALfloat *data, ALuint OutChans, ALfloat (*restrict OutBuffer)[BUFFERSIZE],
|
void Mix_C(const ALfloat *data, ALuint OutChans, ALfloat (*restrict OutBuffer)[BUFFERSIZE],
|
||||||
struct MixGains *Gains, ALuint Counter, ALuint OutPos, ALuint BufferSize);
|
struct MixGains *Gains, ALuint Counter, ALuint OutPos, ALuint BufferSize);
|
||||||
|
|
||||||
/* SSE mixers */
|
/* SSE mixers */
|
||||||
void MixHrtf_SSE(ALfloat (*restrict OutBuffer)[BUFFERSIZE], const ALfloat *data,
|
void MixHrtf_SSE(ALfloat (*restrict OutBuffer)[BUFFERSIZE], const ALfloat *data,
|
||||||
ALuint Counter, ALuint Offset, ALuint OutPos, const ALuint IrSize,
|
ALuint Offset, const ALuint IrSize, const struct HrtfParams *hrtfparams,
|
||||||
const struct HrtfParams *hrtfparams, struct HrtfState *hrtfstate,
|
struct HrtfState *hrtfstate, ALuint BufferSize);
|
||||||
ALuint BufferSize);
|
|
||||||
void Mix_SSE(const ALfloat *data, ALuint OutChans, ALfloat (*restrict OutBuffer)[BUFFERSIZE],
|
void Mix_SSE(const ALfloat *data, ALuint OutChans, ALfloat (*restrict OutBuffer)[BUFFERSIZE],
|
||||||
struct MixGains *Gains, ALuint Counter, ALuint OutPos, ALuint BufferSize);
|
struct MixGains *Gains, ALuint Counter, ALuint OutPos, ALuint BufferSize);
|
||||||
|
|
||||||
@ -56,9 +54,8 @@ const ALfloat *Resample_lerp32_SSE41(const ALfloat *src, ALuint frac, ALuint inc
|
|||||||
|
|
||||||
/* Neon mixers */
|
/* Neon mixers */
|
||||||
void MixHrtf_Neon(ALfloat (*restrict OutBuffer)[BUFFERSIZE], const ALfloat *data,
|
void MixHrtf_Neon(ALfloat (*restrict OutBuffer)[BUFFERSIZE], const ALfloat *data,
|
||||||
ALuint Counter, ALuint Offset, ALuint OutPos, const ALuint IrSize,
|
ALuint Offset, const ALuint IrSize, const struct HrtfParams *hrtfparams,
|
||||||
const struct HrtfParams *hrtfparams, struct HrtfState *hrtfstate,
|
struct HrtfState *hrtfstate, ALuint BufferSize);
|
||||||
ALuint BufferSize);
|
|
||||||
void Mix_Neon(const ALfloat *data, ALuint OutChans, ALfloat (*restrict OutBuffer)[BUFFERSIZE],
|
void Mix_Neon(const ALfloat *data, ALuint OutChans, ALfloat (*restrict OutBuffer)[BUFFERSIZE],
|
||||||
struct MixGains *Gains, ALuint Counter, ALuint OutPos, ALuint BufferSize);
|
struct MixGains *Gains, ALuint Counter, ALuint OutPos, ALuint BufferSize);
|
||||||
|
|
||||||
|
@ -14,11 +14,6 @@
|
|||||||
#define MixHrtf MERGE(MixHrtf_,SUFFIX)
|
#define MixHrtf MERGE(MixHrtf_,SUFFIX)
|
||||||
|
|
||||||
|
|
||||||
static inline void ApplyCoeffsStep(ALuint Offset, ALfloat (*restrict Values)[2],
|
|
||||||
const ALuint irSize,
|
|
||||||
ALfloat (*restrict Coeffs)[2],
|
|
||||||
const ALfloat (*restrict CoeffStep)[2],
|
|
||||||
ALfloat left, ALfloat right);
|
|
||||||
static inline void ApplyCoeffs(ALuint Offset, ALfloat (*restrict Values)[2],
|
static inline void ApplyCoeffs(ALuint Offset, ALfloat (*restrict Values)[2],
|
||||||
const ALuint irSize,
|
const ALuint irSize,
|
||||||
ALfloat (*restrict Coeffs)[2],
|
ALfloat (*restrict Coeffs)[2],
|
||||||
@ -26,7 +21,7 @@ static inline void ApplyCoeffs(ALuint Offset, ALfloat (*restrict Values)[2],
|
|||||||
|
|
||||||
|
|
||||||
void MixHrtf(ALfloat (*restrict OutBuffer)[BUFFERSIZE], const ALfloat *data,
|
void MixHrtf(ALfloat (*restrict OutBuffer)[BUFFERSIZE], const ALfloat *data,
|
||||||
ALuint Counter, ALuint Offset, ALuint OutPos, const ALuint IrSize,
|
ALuint Offset, const ALuint IrSize,
|
||||||
const HrtfParams *hrtfparams, HrtfState *hrtfstate, ALuint BufferSize)
|
const HrtfParams *hrtfparams, HrtfState *hrtfstate, ALuint BufferSize)
|
||||||
{
|
{
|
||||||
alignas(16) ALfloat Coeffs[HRIR_LENGTH][2];
|
alignas(16) ALfloat Coeffs[HRIR_LENGTH][2];
|
||||||
@ -37,52 +32,25 @@ void MixHrtf(ALfloat (*restrict OutBuffer)[BUFFERSIZE], const ALfloat *data,
|
|||||||
|
|
||||||
for(c = 0;c < IrSize;c++)
|
for(c = 0;c < IrSize;c++)
|
||||||
{
|
{
|
||||||
Coeffs[c][0] = hrtfparams->Coeffs[c][0] - (hrtfparams->CoeffStep[c][0]*Counter);
|
Coeffs[c][0] = hrtfparams->Coeffs[c][0];
|
||||||
Coeffs[c][1] = hrtfparams->Coeffs[c][1] - (hrtfparams->CoeffStep[c][1]*Counter);
|
Coeffs[c][1] = hrtfparams->Coeffs[c][1];
|
||||||
}
|
}
|
||||||
Delay[0] = hrtfparams->Delay[0] - (hrtfparams->DelayStep[0]*Counter);
|
Delay[0] = hrtfparams->Delay[0];
|
||||||
Delay[1] = hrtfparams->Delay[1] - (hrtfparams->DelayStep[1]*Counter);
|
Delay[1] = hrtfparams->Delay[1];
|
||||||
|
|
||||||
for(pos = 0;pos < BufferSize && pos < Counter;pos++)
|
for(pos = 0;pos < BufferSize;pos++)
|
||||||
{
|
{
|
||||||
hrtfstate->History[Offset&SRC_HISTORY_MASK] = data[pos];
|
hrtfstate->History[Offset&HRTF_HISTORY_MASK] = data[pos];
|
||||||
left = lerp(hrtfstate->History[(Offset-(Delay[0]>>HRTFDELAY_BITS))&SRC_HISTORY_MASK],
|
left = hrtfstate->History[(Offset-Delay[0])&HRTF_HISTORY_MASK];
|
||||||
hrtfstate->History[(Offset-(Delay[0]>>HRTFDELAY_BITS)-1)&SRC_HISTORY_MASK],
|
right = hrtfstate->History[(Offset-Delay[1])&HRTF_HISTORY_MASK];
|
||||||
(Delay[0]&HRTFDELAY_MASK)*(1.0f/HRTFDELAY_FRACONE));
|
|
||||||
right = lerp(hrtfstate->History[(Offset-(Delay[1]>>HRTFDELAY_BITS))&SRC_HISTORY_MASK],
|
|
||||||
hrtfstate->History[(Offset-(Delay[1]>>HRTFDELAY_BITS)-1)&SRC_HISTORY_MASK],
|
|
||||||
(Delay[1]&HRTFDELAY_MASK)*(1.0f/HRTFDELAY_FRACONE));
|
|
||||||
|
|
||||||
Delay[0] += hrtfparams->DelayStep[0];
|
|
||||||
Delay[1] += hrtfparams->DelayStep[1];
|
|
||||||
|
|
||||||
hrtfstate->Values[(Offset+IrSize)&HRIR_MASK][0] = 0.0f;
|
|
||||||
hrtfstate->Values[(Offset+IrSize)&HRIR_MASK][1] = 0.0f;
|
|
||||||
Offset++;
|
|
||||||
|
|
||||||
ApplyCoeffsStep(Offset, hrtfstate->Values, IrSize, Coeffs, hrtfparams->CoeffStep, left, right);
|
|
||||||
OutBuffer[FrontLeft][OutPos] += hrtfstate->Values[Offset&HRIR_MASK][0];
|
|
||||||
OutBuffer[FrontRight][OutPos] += hrtfstate->Values[Offset&HRIR_MASK][1];
|
|
||||||
OutPos++;
|
|
||||||
}
|
|
||||||
|
|
||||||
Delay[0] >>= HRTFDELAY_BITS;
|
|
||||||
Delay[1] >>= HRTFDELAY_BITS;
|
|
||||||
for(;pos < BufferSize;pos++)
|
|
||||||
{
|
|
||||||
hrtfstate->History[Offset&SRC_HISTORY_MASK] = data[pos];
|
|
||||||
left = hrtfstate->History[(Offset-Delay[0])&SRC_HISTORY_MASK];
|
|
||||||
right = hrtfstate->History[(Offset-Delay[1])&SRC_HISTORY_MASK];
|
|
||||||
|
|
||||||
hrtfstate->Values[(Offset+IrSize)&HRIR_MASK][0] = 0.0f;
|
hrtfstate->Values[(Offset+IrSize)&HRIR_MASK][0] = 0.0f;
|
||||||
hrtfstate->Values[(Offset+IrSize)&HRIR_MASK][1] = 0.0f;
|
hrtfstate->Values[(Offset+IrSize)&HRIR_MASK][1] = 0.0f;
|
||||||
Offset++;
|
Offset++;
|
||||||
|
|
||||||
ApplyCoeffs(Offset, hrtfstate->Values, IrSize, Coeffs, left, right);
|
ApplyCoeffs(Offset, hrtfstate->Values, IrSize, Coeffs, left, right);
|
||||||
OutBuffer[FrontLeft][OutPos] += hrtfstate->Values[Offset&HRIR_MASK][0];
|
OutBuffer[0][pos] += hrtfstate->Values[Offset&HRIR_MASK][0];
|
||||||
OutBuffer[FrontRight][OutPos] += hrtfstate->Values[Offset&HRIR_MASK][1];
|
OutBuffer[1][pos] += hrtfstate->Values[Offset&HRIR_MASK][1];
|
||||||
|
|
||||||
OutPos++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,38 +9,6 @@
|
|||||||
#include "hrtf.h"
|
#include "hrtf.h"
|
||||||
|
|
||||||
|
|
||||||
static inline void ApplyCoeffsStep(ALuint Offset, ALfloat (*restrict Values)[2],
|
|
||||||
const ALuint IrSize,
|
|
||||||
ALfloat (*restrict Coeffs)[2],
|
|
||||||
const ALfloat (*restrict CoeffStep)[2],
|
|
||||||
ALfloat left, ALfloat right)
|
|
||||||
{
|
|
||||||
ALuint c;
|
|
||||||
float32x4_t leftright4;
|
|
||||||
{
|
|
||||||
float32x2_t leftright2 = vdup_n_f32(0.0);
|
|
||||||
leftright2 = vset_lane_f32(left, leftright2, 0);
|
|
||||||
leftright2 = vset_lane_f32(right, leftright2, 1);
|
|
||||||
leftright4 = vcombine_f32(leftright2, leftright2);
|
|
||||||
}
|
|
||||||
for(c = 0;c < IrSize;c += 2)
|
|
||||||
{
|
|
||||||
const ALuint o0 = (Offset+c)&HRIR_MASK;
|
|
||||||
const ALuint o1 = (o0+1)&HRIR_MASK;
|
|
||||||
float32x4_t vals = vcombine_f32(vld1_f32((float32_t*)&Values[o0][0]),
|
|
||||||
vld1_f32((float32_t*)&Values[o1][0]));
|
|
||||||
float32x4_t coefs = vld1q_f32((float32_t*)&Coeffs[c][0]);
|
|
||||||
float32x4_t deltas = vld1q_f32(&CoeffStep[c][0]);
|
|
||||||
|
|
||||||
vals = vmlaq_f32(vals, coefs, leftright4);
|
|
||||||
coefs = vaddq_f32(coefs, deltas);
|
|
||||||
|
|
||||||
vst1_f32((float32_t*)&Values[o0][0], vget_low_f32(vals));
|
|
||||||
vst1_f32((float32_t*)&Values[o1][0], vget_high_f32(vals));
|
|
||||||
vst1q_f32(&Coeffs[c][0], coefs);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void ApplyCoeffs(ALuint Offset, ALfloat (*restrict Values)[2],
|
static inline void ApplyCoeffs(ALuint Offset, ALfloat (*restrict Values)[2],
|
||||||
const ALuint IrSize,
|
const ALuint IrSize,
|
||||||
ALfloat (*restrict Coeffs)[2],
|
ALfloat (*restrict Coeffs)[2],
|
||||||
|
@ -19,68 +19,6 @@
|
|||||||
#include "mixer_defs.h"
|
#include "mixer_defs.h"
|
||||||
|
|
||||||
|
|
||||||
static inline void ApplyCoeffsStep(ALuint Offset, ALfloat (*restrict Values)[2],
|
|
||||||
const ALuint IrSize,
|
|
||||||
ALfloat (*restrict Coeffs)[2],
|
|
||||||
const ALfloat (*restrict CoeffStep)[2],
|
|
||||||
ALfloat left, ALfloat right)
|
|
||||||
{
|
|
||||||
const __m128 lrlr = _mm_setr_ps(left, right, left, right);
|
|
||||||
__m128 coeffs, deltas, imp0, imp1;
|
|
||||||
__m128 vals = _mm_setzero_ps();
|
|
||||||
ALuint i;
|
|
||||||
|
|
||||||
if((Offset&1))
|
|
||||||
{
|
|
||||||
const ALuint o0 = Offset&HRIR_MASK;
|
|
||||||
const ALuint o1 = (Offset+IrSize-1)&HRIR_MASK;
|
|
||||||
|
|
||||||
coeffs = _mm_load_ps(&Coeffs[0][0]);
|
|
||||||
deltas = _mm_load_ps(&CoeffStep[0][0]);
|
|
||||||
vals = _mm_loadl_pi(vals, (__m64*)&Values[o0][0]);
|
|
||||||
imp0 = _mm_mul_ps(lrlr, coeffs);
|
|
||||||
coeffs = _mm_add_ps(coeffs, deltas);
|
|
||||||
vals = _mm_add_ps(imp0, vals);
|
|
||||||
_mm_store_ps(&Coeffs[0][0], coeffs);
|
|
||||||
_mm_storel_pi((__m64*)&Values[o0][0], vals);
|
|
||||||
for(i = 1;i < IrSize-1;i += 2)
|
|
||||||
{
|
|
||||||
const ALuint o2 = (Offset+i)&HRIR_MASK;
|
|
||||||
|
|
||||||
coeffs = _mm_load_ps(&Coeffs[i+1][0]);
|
|
||||||
deltas = _mm_load_ps(&CoeffStep[i+1][0]);
|
|
||||||
vals = _mm_load_ps(&Values[o2][0]);
|
|
||||||
imp1 = _mm_mul_ps(lrlr, coeffs);
|
|
||||||
coeffs = _mm_add_ps(coeffs, deltas);
|
|
||||||
imp0 = _mm_shuffle_ps(imp0, imp1, _MM_SHUFFLE(1, 0, 3, 2));
|
|
||||||
vals = _mm_add_ps(imp0, vals);
|
|
||||||
_mm_store_ps(&Coeffs[i+1][0], coeffs);
|
|
||||||
_mm_store_ps(&Values[o2][0], vals);
|
|
||||||
imp0 = imp1;
|
|
||||||
}
|
|
||||||
vals = _mm_loadl_pi(vals, (__m64*)&Values[o1][0]);
|
|
||||||
imp0 = _mm_movehl_ps(imp0, imp0);
|
|
||||||
vals = _mm_add_ps(imp0, vals);
|
|
||||||
_mm_storel_pi((__m64*)&Values[o1][0], vals);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for(i = 0;i < IrSize;i += 2)
|
|
||||||
{
|
|
||||||
const ALuint o = (Offset + i)&HRIR_MASK;
|
|
||||||
|
|
||||||
coeffs = _mm_load_ps(&Coeffs[i][0]);
|
|
||||||
deltas = _mm_load_ps(&CoeffStep[i][0]);
|
|
||||||
vals = _mm_load_ps(&Values[o][0]);
|
|
||||||
imp0 = _mm_mul_ps(lrlr, coeffs);
|
|
||||||
coeffs = _mm_add_ps(coeffs, deltas);
|
|
||||||
vals = _mm_add_ps(imp0, vals);
|
|
||||||
_mm_store_ps(&Coeffs[i][0], coeffs);
|
|
||||||
_mm_store_ps(&Values[o][0], vals);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void ApplyCoeffs(ALuint Offset, ALfloat (*restrict Values)[2],
|
static inline void ApplyCoeffs(ALuint Offset, ALfloat (*restrict Values)[2],
|
||||||
const ALuint IrSize,
|
const ALuint IrSize,
|
||||||
ALfloat (*restrict Coeffs)[2],
|
ALfloat (*restrict Coeffs)[2],
|
||||||
|
@ -124,6 +124,18 @@ DECL_CONST static inline const char *GetLabelFromChannel(enum Channel channel)
|
|||||||
case BackCenter: return "back-center";
|
case BackCenter: return "back-center";
|
||||||
case SideLeft: return "side-left";
|
case SideLeft: return "side-left";
|
||||||
case SideRight: return "side-right";
|
case SideRight: return "side-right";
|
||||||
|
|
||||||
|
case TopCenter: return "top-center";
|
||||||
|
case BottomCenter: return "bottom-center";
|
||||||
|
case TopFrontLeft: return "top-front-left";
|
||||||
|
case TopFrontRight: return "top-front-right";
|
||||||
|
case TopBackLeft: return "top-back-left";
|
||||||
|
case TopBackRight: return "top-back-right";
|
||||||
|
case BottomFrontLeft: return "bottom-front-left";
|
||||||
|
case BottomFrontRight: return "bottom-front-right";
|
||||||
|
case BottomBackLeft: return "bottom-back-left";
|
||||||
|
case BottomBackRight: return "bottom-back-right";
|
||||||
|
|
||||||
case InvalidChannel: break;
|
case InvalidChannel: break;
|
||||||
}
|
}
|
||||||
return "(unknown)";
|
return "(unknown)";
|
||||||
@ -322,6 +334,21 @@ ALvoid aluInitPanning(ALCdevice *device)
|
|||||||
{ BackRight, { { 0.224752f, -0.295009f, -0.170325f, 0.0f, 0.0f, 0.0f, 0.0f, 0.105349f, 0.182473f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000000f, -0.065799f }, { 0.224752f, -0.225790f, -0.130361f, 0.0f } } },
|
{ BackRight, { { 0.224752f, -0.295009f, -0.170325f, 0.0f, 0.0f, 0.0f, 0.0f, 0.105349f, 0.182473f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000000f, -0.065799f }, { 0.224752f, -0.225790f, -0.130361f, 0.0f } } },
|
||||||
{ SideLeft, { { 0.224739f, 0.000002f, 0.340644f, 0.0f, 0.0f, 0.0f, 0.0f, -0.210697f, 0.000002f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000000f, -0.065795f }, { 0.224739f, 0.000000f, 0.260717f, 0.0f } } },
|
{ SideLeft, { { 0.224739f, 0.000002f, 0.340644f, 0.0f, 0.0f, 0.0f, 0.0f, -0.210697f, 0.000002f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000000f, -0.065795f }, { 0.224739f, 0.000000f, 0.260717f, 0.0f } } },
|
||||||
{ SideRight, { { 0.224739f, 0.000002f, -0.340644f, 0.0f, 0.0f, 0.0f, 0.0f, -0.210697f, -0.000002f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000000f, 0.065795f }, { 0.224739f, 0.000000f, -0.260717f, 0.0f } } },
|
{ SideRight, { { 0.224739f, 0.000002f, -0.340644f, 0.0f, 0.0f, 0.0f, 0.0f, -0.210697f, -0.000002f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000000f, 0.065795f }, { 0.224739f, 0.000000f, -0.260717f, 0.0f } } },
|
||||||
|
}, CubeDiamond[14] = {
|
||||||
|
{ SideLeft, { { 0.130137f, -0.000013f, 0.207620f, 0.000001f, -0.081895f, 0.000001f, 0.000002f, -0.144357f, -0.000015f, -0.000002f, 0.000001f, -0.032339f, -0.000000f, 0.000001f, 0.000005f, -0.057583f }, { 0.130137f, -0.000009f, 0.139199f, 0.000001f } } },
|
||||||
|
{ FrontCenter, { { 0.130131f, 0.207613f, -0.000007f, 0.000001f, -0.081898f, 0.000001f, -0.000000f, 0.144354f, -0.000010f, -0.000002f, -0.032343f, 0.000006f, -0.000000f, -0.000001f, 0.057583f, -0.000004f }, { 0.130131f, 0.139195f, -0.000005f, 0.000001f } } },
|
||||||
|
{ SideRight, { { 0.130140f, 0.000001f, -0.207624f, -0.000001f, -0.081900f, 0.000005f, 0.000001f, -0.144357f, -0.000002f, 0.000002f, -0.000004f, 0.032342f, -0.000000f, -0.000005f, -0.000002f, 0.057580f }, { 0.130140f, 0.000000f, -0.139202f, -0.000000f } } },
|
||||||
|
{ BackCenter, { { 0.130142f, -0.207624f, 0.000006f, -0.000010f, -0.081897f, 0.000011f, 0.000005f, 0.144354f, -0.000006f, 0.000004f, 0.032340f, 0.000000f, -0.000002f, -0.000005f, -0.057579f, 0.000003f }, { 0.130142f, -0.139202f, 0.000004f, -0.000007f } } },
|
||||||
|
{ TopCenter, { { 0.072579f, 0.000006f, 0.000001f, 0.123524f, 0.126630f, 0.000008f, 0.000001f, -0.000002f, 0.000001f, 0.070290f, 0.000005f, 0.000001f, -0.000002f, 0.000001f, -0.000001f, 0.000002f }, { 0.072579f, 0.000004f, 0.000001f, 0.082817f } } },
|
||||||
|
{ BottomCenter, { { 0.072577f, -0.000008f, -0.000004f, -0.123522f, 0.126628f, 0.000012f, 0.000005f, -0.000001f, 0.000002f, -0.070291f, -0.000008f, -0.000002f, 0.000001f, -0.000002f, 0.000000f, -0.000001f }, { 0.072577f, -0.000006f, -0.000003f, -0.082815f } } },
|
||||||
|
{ TopFrontLeft, { { 0.176238f, 0.156939f, 0.156950f, 0.149964f, 0.006362f, 0.101960f, 0.101968f, -0.000003f, 0.117690f, -0.020696f, 0.018718f, 0.018723f, 0.000002f, 0.038069f, -0.025485f, 0.025484f }, { 0.176238f, 0.105220f, 0.105227f, 0.100544f } } },
|
||||||
|
{ TopFrontRight, { { 0.176240f, 0.156940f, -0.156956f, 0.149960f, 0.006356f, 0.101955f, -0.101970f, -0.000007f, -0.117691f, -0.020700f, 0.018719f, -0.018722f, -0.000003f, -0.038066f, -0.025485f, -0.025485f }, { 0.176240f, 0.105220f, -0.105231f, 0.100541f } } },
|
||||||
|
{ TopBackLeft, { { 0.176245f, -0.156957f, 0.156942f, 0.149971f, 0.006355f, -0.101977f, 0.101961f, 0.000003f, -0.117684f, -0.020701f, -0.018724f, 0.018716f, 0.000001f, -0.038069f, 0.025482f, 0.025479f }, { 0.176245f, -0.105232f, 0.105222f, 0.100548f } } },
|
||||||
|
{ TopBackRight, { { 0.176238f, -0.156944f, -0.156942f, 0.149972f, 0.006363f, -0.101976f, -0.101964f, -0.000005f, 0.117687f, -0.020701f, -0.018726f, -0.018716f, 0.000000f, 0.038072f, 0.025486f, -0.025481f }, { 0.176238f, -0.105224f, -0.105222f, 0.100549f } } },
|
||||||
|
{ BottomFrontLeft, { { 0.176248f, 0.156943f, 0.156950f, -0.149981f, 0.006371f, -0.101969f, -0.101967f, -0.000008f, 0.117685f, 0.020695f, 0.018723f, 0.018718f, 0.000000f, -0.038067f, -0.025486f, 0.025479f }, { 0.176248f, 0.105223f, 0.105227f, -0.100555f } } },
|
||||||
|
{ BottomFrontRight, { { 0.176236f, 0.156947f, -0.156945f, -0.149961f, 0.006353f, -0.101971f, 0.101964f, -0.000002f, -0.117689f, 0.020704f, 0.018723f, -0.018718f, -0.000001f, 0.038071f, -0.025484f, -0.025482f }, { 0.176236f, 0.105225f, -0.105224f, -0.100542f } } },
|
||||||
|
{ BottomBackLeft, { { 0.176236f, -0.156936f, 0.156952f, -0.149964f, 0.006358f, 0.101962f, -0.101976f, -0.000005f, -0.117687f, 0.020707f, -0.018720f, 0.018725f, 0.000001f, 0.038071f, 0.025483f, 0.025485f }, { 0.176236f, -0.105218f, 0.105229f, -0.100543f } } },
|
||||||
|
{ BottomBackRight, { { 0.176256f, -0.156956f, -0.156954f, -0.149974f, 0.006366f, 0.101960f, 0.101964f, 0.000003f, 0.117692f, 0.020690f, -0.018718f, -0.018722f, 0.000001f, -0.038064f, 0.025483f, -0.025484f }, { 0.176256f, -0.105232f, -0.105230f, -0.100550f } } },
|
||||||
};
|
};
|
||||||
const ChannelMap *chanmap = NULL;
|
const ChannelMap *chanmap = NULL;
|
||||||
size_t count = 0;
|
size_t count = 0;
|
||||||
@ -329,6 +356,43 @@ ALvoid aluInitPanning(ALCdevice *device)
|
|||||||
memset(device->Channel, 0, sizeof(device->Channel));
|
memset(device->Channel, 0, sizeof(device->Channel));
|
||||||
device->NumChannels = 0;
|
device->NumChannels = 0;
|
||||||
|
|
||||||
|
if(device->Hrtf)
|
||||||
|
{
|
||||||
|
static const struct {
|
||||||
|
enum Channel channel;
|
||||||
|
ALfloat elevation;
|
||||||
|
ALfloat angle;
|
||||||
|
} VirtualChans[14] = {
|
||||||
|
{ FrontCenter, DEG2RAD( 0.0f), DEG2RAD( 0.0f) },
|
||||||
|
{ BackCenter, DEG2RAD( 0.0f), DEG2RAD(-180.0f) },
|
||||||
|
{ SideLeft, DEG2RAD( 0.0f), DEG2RAD( -90.0f) },
|
||||||
|
{ SideRight, DEG2RAD( 0.0f), DEG2RAD( 90.0f) },
|
||||||
|
{ TopFrontLeft, DEG2RAD( 45.0f), DEG2RAD( -45.0f) },
|
||||||
|
{ TopFrontRight, DEG2RAD( 45.0f), DEG2RAD( 45.0f) },
|
||||||
|
{ TopBackLeft, DEG2RAD( 45.0f), DEG2RAD(-135.0f) },
|
||||||
|
{ TopBackRight, DEG2RAD( 45.0f), DEG2RAD( 135.0f) },
|
||||||
|
{ BottomFrontLeft, DEG2RAD(-45.0f), DEG2RAD( -45.0f) },
|
||||||
|
{ BottomFrontRight, DEG2RAD(-45.0f), DEG2RAD( 45.0f) },
|
||||||
|
{ BottomBackLeft, DEG2RAD(-45.0f), DEG2RAD(-135.0f) },
|
||||||
|
{ BottomBackRight, DEG2RAD(-45.0f), DEG2RAD( 135.0f) },
|
||||||
|
{ TopCenter, DEG2RAD( 90.0f), DEG2RAD( 0.0f) },
|
||||||
|
{ BottomCenter, DEG2RAD(-90.0f), DEG2RAD( 0.0f) },
|
||||||
|
};
|
||||||
|
ALuint i;
|
||||||
|
|
||||||
|
count = COUNTOF(CubeDiamond);
|
||||||
|
chanmap = CubeDiamond;
|
||||||
|
|
||||||
|
for(i = 0;i < count;i++)
|
||||||
|
device->ChannelName[i] = VirtualChans[i].channel;
|
||||||
|
SetChannelMap(device, chanmap, count);
|
||||||
|
for(i = 0;i < count;i++)
|
||||||
|
GetLerpedHrtfCoeffs(device->Hrtf, VirtualChans[i].elevation, VirtualChans[i].angle,
|
||||||
|
device->Hrtf_Params[i].Coeffs, device->Hrtf_Params[i].Delay);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if(LoadChannelSetup(device))
|
if(LoadChannelSetup(device))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -37,6 +37,8 @@
|
|||||||
#include "vector.h"
|
#include "vector.h"
|
||||||
#include "alstring.h"
|
#include "alstring.h"
|
||||||
|
|
||||||
|
#include "hrtf.h"
|
||||||
|
|
||||||
#ifndef ALC_SOFT_HRTF
|
#ifndef ALC_SOFT_HRTF
|
||||||
#define ALC_SOFT_HRTF 1
|
#define ALC_SOFT_HRTF 1
|
||||||
#define ALC_HRTF_SOFT 0x1992
|
#define ALC_HRTF_SOFT 0x1992
|
||||||
@ -528,6 +530,17 @@ enum Channel {
|
|||||||
SideLeft,
|
SideLeft,
|
||||||
SideRight,
|
SideRight,
|
||||||
|
|
||||||
|
TopCenter,
|
||||||
|
BottomCenter,
|
||||||
|
TopFrontLeft,
|
||||||
|
TopFrontRight,
|
||||||
|
TopBackLeft,
|
||||||
|
TopBackRight,
|
||||||
|
BottomFrontLeft,
|
||||||
|
BottomFrontRight,
|
||||||
|
BottomBackLeft,
|
||||||
|
BottomBackRight,
|
||||||
|
|
||||||
InvalidChannel
|
InvalidChannel
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -557,7 +570,7 @@ enum DevFmtChannels {
|
|||||||
|
|
||||||
DevFmtChannelsDefault = DevFmtStereo
|
DevFmtChannelsDefault = DevFmtStereo
|
||||||
};
|
};
|
||||||
#define MAX_OUTPUT_CHANNELS (8)
|
#define MAX_OUTPUT_CHANNELS (14)
|
||||||
|
|
||||||
ALuint BytesFromDevFmt(enum DevFmtType type) DECL_CONST;
|
ALuint BytesFromDevFmt(enum DevFmtType type) DECL_CONST;
|
||||||
ALuint ChannelsFromDevFmt(enum DevFmtChannels chans) DECL_CONST;
|
ALuint ChannelsFromDevFmt(enum DevFmtChannels chans) DECL_CONST;
|
||||||
@ -593,6 +606,21 @@ typedef struct ChannelConfig {
|
|||||||
} ChannelConfig;
|
} ChannelConfig;
|
||||||
|
|
||||||
|
|
||||||
|
#define HRTF_HISTORY_BITS (6)
|
||||||
|
#define HRTF_HISTORY_LENGTH (1<<HRTF_HISTORY_BITS)
|
||||||
|
#define HRTF_HISTORY_MASK (HRTF_HISTORY_LENGTH-1)
|
||||||
|
|
||||||
|
typedef struct HrtfState {
|
||||||
|
alignas(16) ALfloat History[HRTF_HISTORY_LENGTH];
|
||||||
|
alignas(16) ALfloat Values[HRIR_LENGTH][2];
|
||||||
|
} HrtfState;
|
||||||
|
|
||||||
|
typedef struct HrtfParams {
|
||||||
|
alignas(16) ALfloat Coeffs[HRIR_LENGTH][2];
|
||||||
|
ALuint Delay[2];
|
||||||
|
} HrtfParams;
|
||||||
|
|
||||||
|
|
||||||
/* Size for temporary storage of buffer data, in ALfloats. Larger values need
|
/* Size for temporary storage of buffer data, in ALfloats. Larger values need
|
||||||
* more memory, while smaller values may need more iterations. The value needs
|
* more memory, while smaller values may need more iterations. The value needs
|
||||||
* to be a sensible size, however, as it constrains the max stepping value used
|
* to be a sensible size, however, as it constrains the max stepping value used
|
||||||
@ -652,6 +680,9 @@ struct ALCdevice_struct
|
|||||||
|
|
||||||
/* HRTF filter tables */
|
/* HRTF filter tables */
|
||||||
const struct Hrtf *Hrtf;
|
const struct Hrtf *Hrtf;
|
||||||
|
HrtfState Hrtf_State[MAX_OUTPUT_CHANNELS];
|
||||||
|
HrtfParams Hrtf_Params[MAX_OUTPUT_CHANNELS];
|
||||||
|
ALuint Hrtf_Offset;
|
||||||
|
|
||||||
// Stereo-to-binaural filter
|
// Stereo-to-binaural filter
|
||||||
struct bs2b *Bs2b;
|
struct bs2b *Bs2b;
|
||||||
|
@ -30,10 +30,6 @@
|
|||||||
#define RAD2DEG(x) ((ALfloat)(x) * (180.0f/F_PI))
|
#define RAD2DEG(x) ((ALfloat)(x) * (180.0f/F_PI))
|
||||||
|
|
||||||
|
|
||||||
#define SRC_HISTORY_BITS (6)
|
|
||||||
#define SRC_HISTORY_LENGTH (1<<SRC_HISTORY_BITS)
|
|
||||||
#define SRC_HISTORY_MASK (SRC_HISTORY_LENGTH-1)
|
|
||||||
|
|
||||||
#define MAX_PITCH (10)
|
#define MAX_PITCH (10)
|
||||||
|
|
||||||
|
|
||||||
@ -53,19 +49,6 @@ enum ActiveFilters {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
typedef struct HrtfState {
|
|
||||||
alignas(16) ALfloat History[SRC_HISTORY_LENGTH];
|
|
||||||
alignas(16) ALfloat Values[HRIR_LENGTH][2];
|
|
||||||
} HrtfState;
|
|
||||||
|
|
||||||
typedef struct HrtfParams {
|
|
||||||
alignas(16) ALfloat Coeffs[HRIR_LENGTH][2];
|
|
||||||
alignas(16) ALfloat CoeffStep[HRIR_LENGTH][2];
|
|
||||||
ALuint Delay[2];
|
|
||||||
ALint DelayStep[2];
|
|
||||||
} HrtfParams;
|
|
||||||
|
|
||||||
|
|
||||||
typedef struct MixGains {
|
typedef struct MixGains {
|
||||||
ALfloat Current;
|
ALfloat Current;
|
||||||
ALfloat Step;
|
ALfloat Step;
|
||||||
@ -88,14 +71,6 @@ typedef struct DirectParams {
|
|||||||
} Filters[MAX_INPUT_CHANNELS];
|
} Filters[MAX_INPUT_CHANNELS];
|
||||||
|
|
||||||
union {
|
union {
|
||||||
struct {
|
|
||||||
HrtfParams Params[MAX_INPUT_CHANNELS];
|
|
||||||
HrtfState State[MAX_INPUT_CHANNELS];
|
|
||||||
ALuint IrSize;
|
|
||||||
ALfloat Gain;
|
|
||||||
ALfloat Dir[3];
|
|
||||||
} Hrtf;
|
|
||||||
|
|
||||||
MixGains Gains[MAX_INPUT_CHANNELS][MAX_OUTPUT_CHANNELS];
|
MixGains Gains[MAX_INPUT_CHANNELS][MAX_OUTPUT_CHANNELS];
|
||||||
} Mix;
|
} Mix;
|
||||||
} DirectParams;
|
} DirectParams;
|
||||||
@ -125,8 +100,7 @@ typedef void (*MixerFunc)(const ALfloat *data, ALuint OutChans,
|
|||||||
ALfloat (*restrict OutBuffer)[BUFFERSIZE], struct MixGains *Gains,
|
ALfloat (*restrict OutBuffer)[BUFFERSIZE], struct MixGains *Gains,
|
||||||
ALuint Counter, ALuint OutPos, ALuint BufferSize);
|
ALuint Counter, ALuint OutPos, ALuint BufferSize);
|
||||||
typedef void (*HrtfMixerFunc)(ALfloat (*restrict OutBuffer)[BUFFERSIZE], const ALfloat *data,
|
typedef void (*HrtfMixerFunc)(ALfloat (*restrict OutBuffer)[BUFFERSIZE], const ALfloat *data,
|
||||||
ALuint Counter, ALuint Offset, ALuint OutPos,
|
ALuint Offset, const ALuint IrSize, const HrtfParams *hrtfparams,
|
||||||
const ALuint IrSize, const HrtfParams *hrtfparams,
|
|
||||||
HrtfState *hrtfstate, ALuint BufferSize);
|
HrtfState *hrtfstate, ALuint BufferSize);
|
||||||
|
|
||||||
|
|
||||||
|
@ -2599,21 +2599,10 @@ ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state)
|
|||||||
|
|
||||||
voice->Direct.Moving = AL_FALSE;
|
voice->Direct.Moving = AL_FALSE;
|
||||||
voice->Direct.Counter = 0;
|
voice->Direct.Counter = 0;
|
||||||
for(i = 0;i < MAX_INPUT_CHANNELS;i++)
|
|
||||||
{
|
|
||||||
ALsizei j;
|
|
||||||
for(j = 0;j < SRC_HISTORY_LENGTH;j++)
|
|
||||||
voice->Direct.Mix.Hrtf.State[i].History[j] = 0.0f;
|
|
||||||
for(j = 0;j < HRIR_LENGTH;j++)
|
|
||||||
{
|
|
||||||
voice->Direct.Mix.Hrtf.State[i].Values[j][0] = 0.0f;
|
|
||||||
voice->Direct.Mix.Hrtf.State[i].Values[j][1] = 0.0f;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for(i = 0;i < (ALsizei)device->NumAuxSends;i++)
|
for(i = 0;i < (ALsizei)device->NumAuxSends;i++)
|
||||||
{
|
{
|
||||||
voice->Send[i].Counter = 0;
|
|
||||||
voice->Send[i].Moving = AL_FALSE;
|
voice->Send[i].Moving = AL_FALSE;
|
||||||
|
voice->Send[i].Counter = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(BufferList->buffer->FmtChannels == FmtMono)
|
if(BufferList->buffer->FmtChannels == FmtMono)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user