a27e5e1652
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.
110 lines
3.7 KiB
C
110 lines
3.7 KiB
C
#include "config.h"
|
|
|
|
#include <assert.h>
|
|
|
|
#include "alMain.h"
|
|
#include "alu.h"
|
|
#include "alSource.h"
|
|
#include "alAuxEffectSlot.h"
|
|
|
|
|
|
static inline ALfloat point32(const ALfloat *vals, ALuint UNUSED(frac))
|
|
{ return vals[0]; }
|
|
static inline ALfloat lerp32(const ALfloat *vals, ALuint frac)
|
|
{ return lerp(vals[0], vals[1], frac * (1.0f/FRACTIONONE)); }
|
|
static inline ALfloat cubic32(const ALfloat *vals, ALuint frac)
|
|
{ return cubic(vals[-1], vals[0], vals[1], vals[2], frac * (1.0f/FRACTIONONE)); }
|
|
|
|
const ALfloat *Resample_copy32_C(const ALfloat *src, ALuint UNUSED(frac),
|
|
ALuint increment, ALfloat *restrict dst, ALuint numsamples)
|
|
{
|
|
assert(increment==FRACTIONONE);
|
|
#if defined(HAVE_SSE) || defined(HAVE_NEON)
|
|
/* Avoid copying the source data if it's aligned like the destination. */
|
|
if((((intptr_t)src)&15) == (((intptr_t)dst)&15))
|
|
return src;
|
|
#endif
|
|
memcpy(dst, src, numsamples*sizeof(ALfloat));
|
|
return dst;
|
|
}
|
|
|
|
#define DECL_TEMPLATE(Sampler) \
|
|
const ALfloat *Resample_##Sampler##_C(const ALfloat *src, ALuint frac, \
|
|
ALuint increment, ALfloat *restrict dst, ALuint numsamples) \
|
|
{ \
|
|
ALuint i; \
|
|
for(i = 0;i < numsamples;i++) \
|
|
{ \
|
|
dst[i] = Sampler(src, frac); \
|
|
\
|
|
frac += increment; \
|
|
src += frac>>FRACTIONBITS; \
|
|
frac &= FRACTIONMASK; \
|
|
} \
|
|
return dst; \
|
|
}
|
|
|
|
DECL_TEMPLATE(point32)
|
|
DECL_TEMPLATE(lerp32)
|
|
DECL_TEMPLATE(cubic32)
|
|
|
|
#undef DECL_TEMPLATE
|
|
|
|
|
|
void ALfilterState_processC(ALfilterState *filter, ALfloat *restrict dst, const ALfloat *src, ALuint numsamples)
|
|
{
|
|
ALuint i;
|
|
for(i = 0;i < numsamples;i++)
|
|
*(dst++) = ALfilterState_processSingle(filter, *(src++));
|
|
}
|
|
|
|
|
|
static inline void ApplyCoeffs(ALuint Offset, ALfloat (*restrict Values)[2],
|
|
const ALuint IrSize,
|
|
ALfloat (*restrict Coeffs)[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;
|
|
}
|
|
}
|
|
|
|
#define SUFFIX C
|
|
#include "mixer_inc.c"
|
|
#undef SUFFIX
|
|
|
|
|
|
void Mix_C(const ALfloat *data, ALuint OutChans, ALfloat (*restrict OutBuffer)[BUFFERSIZE],
|
|
MixGains *Gains, ALuint Counter, ALuint OutPos, ALuint BufferSize)
|
|
{
|
|
ALfloat gain, step;
|
|
ALuint c;
|
|
|
|
for(c = 0;c < OutChans;c++)
|
|
{
|
|
ALuint pos = 0;
|
|
gain = Gains[c].Current;
|
|
step = Gains[c].Step;
|
|
if(step != 1.0f && Counter > 0)
|
|
{
|
|
for(;pos < BufferSize && pos < Counter;pos++)
|
|
{
|
|
OutBuffer[c][OutPos+pos] += data[pos]*gain;
|
|
gain *= step;
|
|
}
|
|
if(pos == Counter)
|
|
gain = Gains[c].Target;
|
|
Gains[c].Current = gain;
|
|
}
|
|
|
|
if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD))
|
|
continue;
|
|
for(;pos < BufferSize;pos++)
|
|
OutBuffer[c][OutPos+pos] += data[pos]*gain;
|
|
}
|
|
}
|