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.
439 lines
22 KiB
C
439 lines
22 KiB
C
/**
|
|
* OpenAL cross platform audio library
|
|
* Copyright (C) 1999-2010 by authors.
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Library General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Library General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Library General Public
|
|
* License along with this library; if not, write to the
|
|
* Free Software Foundation, Inc.,
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
* Or go to http://www.gnu.org/copyleft/lgpl.html
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include <math.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <ctype.h>
|
|
#include <assert.h>
|
|
|
|
#include "alMain.h"
|
|
#include "AL/al.h"
|
|
#include "AL/alc.h"
|
|
#include "alu.h"
|
|
#include "bool.h"
|
|
|
|
|
|
void ComputeAngleGains(const ALCdevice *device, ALfloat angle, ALfloat elevation, ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS])
|
|
{
|
|
ALfloat dir[3] = {
|
|
sinf(angle) * cosf(elevation),
|
|
sinf(elevation),
|
|
-cosf(angle) * cosf(elevation)
|
|
};
|
|
ComputeDirectionalGains(device, dir, ingain, gains);
|
|
}
|
|
|
|
void ComputeDirectionalGains(const ALCdevice *device, const ALfloat dir[3], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS])
|
|
{
|
|
ALfloat coeffs[MAX_AMBI_COEFFS];
|
|
ALuint i, j;
|
|
/* Convert from OpenAL coords to Ambisonics. */
|
|
ALfloat x = -dir[2];
|
|
ALfloat y = -dir[0];
|
|
ALfloat z = dir[1];
|
|
|
|
coeffs[0] = 0.7071f; /* sqrt(1.0 / 2.0) */
|
|
coeffs[1] = x; /* X */
|
|
coeffs[2] = y; /* Y */
|
|
coeffs[3] = z; /* Z */
|
|
coeffs[4] = 0.5f * (3.0f*z*z - 1.0f); /* 0.5 * (3*Z*Z - 1) */
|
|
coeffs[5] = 2.0f * z * x; /* 2*Z*X */
|
|
coeffs[6] = 2.0f * y * z; /* 2*Y*Z */
|
|
coeffs[7] = x*x - y*y; /* X*X - Y*Y */
|
|
coeffs[8] = 2.0f * x * y; /* 2*X*Y */
|
|
coeffs[9] = 0.5f * z * (5.0f*z*z - 3.0f); /* 0.5 * Z * (5*Z*Z - 3) */
|
|
coeffs[10] = 0.7262f * x * (5.0f*z*z - 1.0f); /* sqrt(135.0 / 256.0) * X * (5*Z*Z - 1) */
|
|
coeffs[11] = 0.7262f * y * (5.0f*z*z - 1.0f); /* sqrt(135.0 / 256.0) * Y * (5*Z*Z - 1) */
|
|
coeffs[12] = 2.5981f * z * (x*x - y*y); /* sqrt(27.0 / 4.0) * Z * (X*X - Y*Y) */
|
|
coeffs[13] = 5.1962f * x * y * z; /* sqrt(27) * X * Y * Z */
|
|
coeffs[14] = x * (x*x - 3.0f*y*y); /* X * (X*X - 3*Y*Y) */
|
|
coeffs[15] = y * (3.0f*x*x - y*y); /* Y * (3*X*X - Y*Y) */
|
|
|
|
for(i = 0;i < MAX_OUTPUT_CHANNELS;i++)
|
|
gains[i] = 0.0f;
|
|
for(i = 0;i < device->NumChannels;i++)
|
|
{
|
|
for(j = 0;j < MAX_AMBI_COEFFS;j++)
|
|
gains[i] += device->Channel[i].HOACoeff[j]*coeffs[j];
|
|
gains[i] = maxf(gains[i], 0.0f) * ingain;
|
|
}
|
|
}
|
|
|
|
void ComputeAmbientGains(const ALCdevice *device, ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS])
|
|
{
|
|
ALuint i;
|
|
|
|
for(i = 0;i < MAX_OUTPUT_CHANNELS;i++)
|
|
gains[i] = 0.0f;
|
|
for(i = 0;i < device->NumChannels;i++)
|
|
{
|
|
// The W coefficients are based on a mathematical average of the
|
|
// output, scaled by sqrt(2) to compensate for FuMa-style Ambisonics
|
|
// scaling the W channel input by sqrt(0.5). The square root of the
|
|
// base average provides for a more perceptual average volume, better
|
|
// suited to non-directional gains.
|
|
gains[i] = sqrtf(device->Channel[i].HOACoeff[0]/1.4142f)*1.4142f * ingain;
|
|
}
|
|
}
|
|
|
|
void ComputeBFormatGains(const ALCdevice *device, const ALfloat mtx[4], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS])
|
|
{
|
|
ALuint i, j;
|
|
|
|
for(i = 0;i < MAX_OUTPUT_CHANNELS;i++)
|
|
gains[i] = 0.0f;
|
|
for(i = 0;i < device->NumChannels;i++)
|
|
{
|
|
for(j = 0;j < 4;j++)
|
|
gains[i] += device->Channel[i].FOACoeff[j] * mtx[j];
|
|
gains[i] *= ingain;
|
|
}
|
|
}
|
|
|
|
|
|
DECL_CONST static inline const char *GetLabelFromChannel(enum Channel channel)
|
|
{
|
|
switch(channel)
|
|
{
|
|
case FrontLeft: return "front-left";
|
|
case FrontRight: return "front-right";
|
|
case FrontCenter: return "front-center";
|
|
case LFE: return "lfe";
|
|
case BackLeft: return "back-left";
|
|
case BackRight: return "back-right";
|
|
case BackCenter: return "back-center";
|
|
case SideLeft: return "side-left";
|
|
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;
|
|
}
|
|
return "(unknown)";
|
|
}
|
|
|
|
|
|
typedef struct ChannelMap {
|
|
enum Channel ChanName;
|
|
ChannelConfig Config;
|
|
} ChannelMap;
|
|
|
|
static void SetChannelMap(ALCdevice *device, const ChannelMap *chanmap, size_t count)
|
|
{
|
|
size_t i, j;
|
|
|
|
for(i = 0;i < MAX_OUTPUT_CHANNELS && device->ChannelName[i] != InvalidChannel;i++)
|
|
{
|
|
if(device->ChannelName[i] == LFE)
|
|
{
|
|
for(j = 0;j < MAX_AMBI_COEFFS;j++)
|
|
device->Channel[i].HOACoeff[j] = 0.0f;
|
|
for(j = 0;j < 4;j++)
|
|
device->Channel[i].FOACoeff[j] = 0.0f;
|
|
continue;
|
|
}
|
|
|
|
for(j = 0;j < count;j++)
|
|
{
|
|
if(device->ChannelName[i] == chanmap[j].ChanName)
|
|
{
|
|
device->Channel[i] = chanmap[j].Config;
|
|
break;
|
|
}
|
|
}
|
|
if(j == count)
|
|
ERR("Failed to match %s channel ("SZFMT") in config\n", GetLabelFromChannel(device->ChannelName[i]), i);
|
|
}
|
|
device->NumChannels = i;
|
|
}
|
|
|
|
static bool LoadChannelSetup(ALCdevice *device)
|
|
{
|
|
static const enum Channel mono_chans[1] = {
|
|
FrontCenter
|
|
}, stereo_chans[2] = {
|
|
FrontLeft, FrontRight
|
|
}, quad_chans[4] = {
|
|
FrontLeft, FrontRight,
|
|
BackLeft, BackRight
|
|
}, surround51_chans[5] = {
|
|
FrontLeft, FrontRight, FrontCenter,
|
|
SideLeft, SideRight
|
|
}, surround51rear_chans[5] = {
|
|
FrontLeft, FrontRight, FrontCenter,
|
|
BackLeft, BackRight
|
|
}, surround61_chans[6] = {
|
|
FrontLeft, FrontRight,
|
|
FrontCenter, BackCenter,
|
|
SideLeft, SideRight
|
|
}, surround71_chans[7] = {
|
|
FrontLeft, FrontRight, FrontCenter,
|
|
BackLeft, BackRight,
|
|
SideLeft, SideRight
|
|
};
|
|
ChannelMap chanmap[MAX_OUTPUT_CHANNELS];
|
|
const enum Channel *channels = NULL;
|
|
const char *layout = NULL;
|
|
size_t count = 0;
|
|
size_t i;
|
|
|
|
switch(device->FmtChans)
|
|
{
|
|
case DevFmtMono:
|
|
layout = "mono";
|
|
channels = mono_chans;
|
|
count = COUNTOF(mono_chans);
|
|
break;
|
|
case DevFmtStereo:
|
|
layout = "stereo";
|
|
channels = stereo_chans;
|
|
count = COUNTOF(stereo_chans);
|
|
break;
|
|
case DevFmtQuad:
|
|
layout = "quad";
|
|
channels = quad_chans;
|
|
count = COUNTOF(quad_chans);
|
|
break;
|
|
case DevFmtX51:
|
|
layout = "surround51";
|
|
channels = surround51_chans;
|
|
count = COUNTOF(surround51_chans);
|
|
break;
|
|
case DevFmtX51Rear:
|
|
layout = "surround51rear";
|
|
channels = surround51rear_chans;
|
|
count = COUNTOF(surround51rear_chans);
|
|
break;
|
|
case DevFmtX61:
|
|
layout = "surround61";
|
|
channels = surround61_chans;
|
|
count = COUNTOF(surround61_chans);
|
|
break;
|
|
case DevFmtX71:
|
|
layout = "surround71";
|
|
channels = surround71_chans;
|
|
count = COUNTOF(surround71_chans);
|
|
break;
|
|
}
|
|
|
|
if(!layout)
|
|
return false;
|
|
else
|
|
{
|
|
char name[32];
|
|
snprintf(name, sizeof(name), "%s/enable", layout);
|
|
if(!GetConfigValueBool("layouts", name, 0))
|
|
return false;
|
|
}
|
|
|
|
for(i = 0;i < count;i++)
|
|
{
|
|
const char *channame;
|
|
char chanlayout[32];
|
|
const char *value;
|
|
int props;
|
|
|
|
chanmap[i].ChanName = channels[i];
|
|
channame = GetLabelFromChannel(channels[i]);
|
|
|
|
snprintf(chanlayout, sizeof(chanlayout), "%s/%s", layout, channame);
|
|
if(!ConfigValueStr("layouts", chanlayout, &value))
|
|
{
|
|
ERR("Missing channel %s\n", channame);
|
|
return false;
|
|
}
|
|
props = sscanf(value, " %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f ; %f %f %f %f",
|
|
&chanmap[i].Config.HOACoeff[0], &chanmap[i].Config.HOACoeff[1], &chanmap[i].Config.HOACoeff[2],
|
|
&chanmap[i].Config.HOACoeff[3], &chanmap[i].Config.HOACoeff[4], &chanmap[i].Config.HOACoeff[5],
|
|
&chanmap[i].Config.HOACoeff[6], &chanmap[i].Config.HOACoeff[7], &chanmap[i].Config.HOACoeff[8],
|
|
&chanmap[i].Config.HOACoeff[9], &chanmap[i].Config.HOACoeff[10], &chanmap[i].Config.HOACoeff[11],
|
|
&chanmap[i].Config.HOACoeff[12], &chanmap[i].Config.HOACoeff[13], &chanmap[i].Config.HOACoeff[14],
|
|
&chanmap[i].Config.HOACoeff[15], &chanmap[i].Config.FOACoeff[0], &chanmap[i].Config.FOACoeff[1],
|
|
&chanmap[i].Config.FOACoeff[2], &chanmap[i].Config.FOACoeff[3]);
|
|
if(props == 0)
|
|
{
|
|
ERR("Failed to parse %s channel's properties\n", channame);
|
|
return false;
|
|
}
|
|
|
|
if(props < 20)
|
|
{
|
|
ERR("Failed to parse %s channel's elements (expected 20, got %d)\n", channame, props);
|
|
return false;
|
|
}
|
|
}
|
|
SetChannelMap(device, chanmap, count);
|
|
return true;
|
|
}
|
|
|
|
ALvoid aluInitPanning(ALCdevice *device)
|
|
{
|
|
static const ChannelMap MonoCfg[1] = {
|
|
{ FrontCenter, { { 1.4142f }, { 1.4142f } } },
|
|
}, StereoCfg[2] = {
|
|
{ FrontLeft, { { 0.7071f, 0.0f, 0.5f, 0.0f }, { 0.7071f, 0.0f, 0.5f, 0.0f } } },
|
|
{ FrontRight, { { 0.7071f, 0.0f, -0.5f, 0.0f }, { 0.7071f, 0.0f, -0.5f, 0.0f } } },
|
|
}, QuadCfg[4] = {
|
|
{ FrontLeft, { { 0.353558f, 0.306181f, 0.306192f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000000f, 0.117183f }, { 0.353553f, 0.250000f, 0.250000f, 0.0f } } },
|
|
{ FrontRight, { { 0.353558f, 0.306181f, -0.306192f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000000f, -0.117183f }, { 0.353553f, 0.250000f, -0.250000f, 0.0f } } },
|
|
{ BackLeft, { { 0.353543f, -0.306192f, 0.306181f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000000f, -0.117193f }, { 0.353553f, -0.250000f, 0.250000f, 0.0f } } },
|
|
{ BackRight, { { 0.353543f, -0.306192f, -0.306181f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000000f, 0.117193f }, { 0.353553f, -0.250000f, -0.250000f, 0.0f } } },
|
|
}, X51SideCfg[5] = {
|
|
{ FrontLeft, { { 0.208954f, 0.212846f, 0.238350f, 0.0f, 0.0f, 0.0f, 0.0f, -0.017738f, 0.204014f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -0.051023f, 0.047490f }, { 0.208954f, 0.162905f, 0.182425f, 0.0f } } },
|
|
{ FrontRight, { { 0.208954f, 0.212846f, -0.238350f, 0.0f, 0.0f, 0.0f, 0.0f, -0.017738f, -0.204014f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -0.051023f, -0.047490f }, { 0.208954f, 0.162905f, -0.182425f, 0.0f } } },
|
|
{ FrontCenter, { { 0.109403f, 0.179490f, 0.000000f, 0.0f, 0.0f, 0.0f, 0.0f, 0.142031f, -0.000002f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.072024f, -0.000001f }, { 0.109403f, 0.137375f, 0.000000f, 0.0f } } },
|
|
{ SideLeft, { { 0.470936f, -0.369626f, 0.349386f, 0.0f, 0.0f, 0.0f, 0.0f, -0.031375f, -0.058144f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -0.007119f, -0.043968f }, { 0.470934f, -0.282903f, 0.267406f, 0.0f } } },
|
|
{ SideRight, { { 0.470936f, -0.369626f, -0.349386f, 0.0f, 0.0f, 0.0f, 0.0f, -0.031375f, 0.058144f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -0.007119f, 0.043968f }, { 0.470934f, -0.282903f, -0.267406f, 0.0f } } },
|
|
}, X51RearCfg[5] = {
|
|
{ FrontLeft, { { 0.208954f, 0.212846f, 0.238350f, 0.0f, 0.0f, 0.0f, 0.0f, -0.017738f, 0.204014f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -0.051023f, 0.047490f }, { 0.208954f, 0.162905f, 0.182425f, 0.0f } } },
|
|
{ FrontRight, { { 0.208954f, 0.212846f, -0.238350f, 0.0f, 0.0f, 0.0f, 0.0f, -0.017738f, -0.204014f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -0.051023f, -0.047490f }, { 0.208954f, 0.162905f, -0.182425f, 0.0f } } },
|
|
{ FrontCenter, { { 0.109403f, 0.179490f, 0.000000f, 0.0f, 0.0f, 0.0f, 0.0f, 0.142031f, -0.000002f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.072024f, -0.000001f }, { 0.109403f, 0.137375f, 0.000000f, 0.0f } } },
|
|
{ BackLeft, { { 0.470936f, -0.369626f, 0.349386f, 0.0f, 0.0f, 0.0f, 0.0f, -0.031375f, -0.058144f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -0.007119f, -0.043968f }, { 0.470934f, -0.282903f, 0.267406f, 0.0f } } },
|
|
{ BackRight, { { 0.470936f, -0.369626f, -0.349386f, 0.0f, 0.0f, 0.0f, 0.0f, -0.031375f, 0.058144f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -0.007119f, 0.043968f }, { 0.470934f, -0.282903f, -0.267406f, 0.0f } } },
|
|
}, X61Cfg[6] = {
|
|
{ FrontLeft, { { 0.167065f, 0.200583f, 0.172695f, 0.0f, 0.0f, 0.0f, 0.0f, 0.029855f, 0.186407f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -0.039241f, 0.068910f }, { 0.167065f, 0.153519f, 0.132175f, 0.0f } } },
|
|
{ FrontRight, { { 0.167065f, 0.200583f, -0.172695f, 0.0f, 0.0f, 0.0f, 0.0f, 0.029855f, -0.186407f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -0.039241f, -0.068910f }, { 0.167065f, 0.153519f, -0.132175f, 0.0f } } },
|
|
{ FrontCenter, { { 0.109403f, 0.179490f, 0.000000f, 0.0f, 0.0f, 0.0f, 0.0f, 0.142031f, 0.000000f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.072024f, -0.000001f }, { 0.109403f, 0.137375f, 0.000000f, 0.0f } } },
|
|
{ BackCenter, { { 0.353556f, -0.461940f, 0.000000f, 0.0f, 0.0f, 0.0f, 0.0f, 0.165723f, 0.000000f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000000f, 0.000005f }, { 0.353556f, -0.353554f, 0.000000f, 0.0f } } },
|
|
{ SideLeft, { { 0.289151f, -0.081301f, 0.401292f, 0.0f, 0.0f, 0.0f, 0.0f, -0.188208f, -0.071420f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.010099f, -0.032897f }, { 0.289151f, -0.062225f, 0.307136f, 0.0f } } },
|
|
{ SideRight, { { 0.289151f, -0.081301f, -0.401292f, 0.0f, 0.0f, 0.0f, 0.0f, -0.188208f, 0.071420f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.010099f, 0.032897f }, { 0.289151f, -0.062225f, -0.307136f, 0.0f } } },
|
|
}, X71Cfg[7] = {
|
|
{ FrontLeft, { { 0.167065f, 0.200583f, 0.172695f, 0.0f, 0.0f, 0.0f, 0.0f, 0.029855f, 0.186407f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -0.039241f, 0.068910f }, { 0.167065f, 0.153519f, 0.132175f, 0.0f } } },
|
|
{ FrontRight, { { 0.167065f, 0.200583f, -0.172695f, 0.0f, 0.0f, 0.0f, 0.0f, 0.029855f, -0.186407f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -0.039241f, -0.068910f }, { 0.167065f, 0.153519f, -0.132175f, 0.0f } } },
|
|
{ FrontCenter, { { 0.109403f, 0.179490f, 0.000000f, 0.0f, 0.0f, 0.0f, 0.0f, 0.142031f, 0.000000f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.072024f, 0.000000f }, { 0.109403f, 0.137375f, 0.000000f, 0.0f } } },
|
|
{ BackLeft, { { 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 } } },
|
|
{ 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;
|
|
size_t count = 0;
|
|
|
|
memset(device->Channel, 0, sizeof(device->Channel));
|
|
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))
|
|
return;
|
|
|
|
switch(device->FmtChans)
|
|
{
|
|
case DevFmtMono:
|
|
count = COUNTOF(MonoCfg);
|
|
chanmap = MonoCfg;
|
|
break;
|
|
|
|
case DevFmtStereo:
|
|
count = COUNTOF(StereoCfg);
|
|
chanmap = StereoCfg;
|
|
break;
|
|
|
|
case DevFmtQuad:
|
|
count = COUNTOF(QuadCfg);
|
|
chanmap = QuadCfg;
|
|
break;
|
|
|
|
case DevFmtX51:
|
|
count = COUNTOF(X51SideCfg);
|
|
chanmap = X51SideCfg;
|
|
break;
|
|
|
|
case DevFmtX51Rear:
|
|
count = COUNTOF(X51RearCfg);
|
|
chanmap = X51RearCfg;
|
|
break;
|
|
|
|
case DevFmtX61:
|
|
count = COUNTOF(X61Cfg);
|
|
chanmap = X61Cfg;
|
|
break;
|
|
|
|
case DevFmtX71:
|
|
count = COUNTOF(X71Cfg);
|
|
chanmap = X71Cfg;
|
|
break;
|
|
}
|
|
|
|
SetChannelMap(device, chanmap, count);
|
|
}
|