aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChris Robinson <[email protected]>2014-11-10 17:53:42 -0800
committerChris Robinson <[email protected]>2014-11-10 17:53:42 -0800
commite036cca1c98e62477ea2f986414f71e2abc25cc4 (patch)
tree7deb72be642b64047a0f823f117c9fd4728fda9c
parent1c4055419ed390aabe5b32429bb3c0f593c2bf08 (diff)
Add the ability to use custom output channel coefficients
I'm not sure exactly how I want to do this yet, but this is a good starting point.
-rw-r--r--Alc/panning.c186
1 files changed, 186 insertions, 0 deletions
diff --git a/Alc/panning.c b/Alc/panning.c
index 21bb7d8e..1f6270f2 100644
--- a/Alc/panning.c
+++ b/Alc/panning.c
@@ -30,6 +30,7 @@
#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])
@@ -108,6 +109,188 @@ typedef struct ChannelMap {
ChannelConfig Config;
} ChannelMap;
+static bool LoadChannelSetup(ALCdevice *device)
+{
+ static const char *mono_names[1] = {
+ "front-center"
+ }, *stereo_names[2] = {
+ "front-left", "front-right"
+ }, *quad_names[4] = {
+ "front-left", "front-right",
+ "back-left", "back-right"
+ }, *surround51_names[6] = {
+ "front-left", "front-right",
+ "front-center", "lfe",
+ "side-left", "side-right"
+ }, *surround51rear_names[6] = {
+ "front-left", "front-right",
+ "front-center", "lfe",
+ "back-left", "back-right"
+ }, *surround61_names[7] = {
+ "front-left", "front-right",
+ "front-center", "lfe", "back-center",
+ "side-left", "side-right"
+ }, *surround71_names[8] = {
+ "front-left", "front-right",
+ "front-center", "lfe",
+ "back-left", "back-right",
+ "side-left", "side-right"
+ };
+ ChannelMap chanmap[MAX_OUTPUT_CHANNELS] = {};
+ const char **channames = NULL;
+ const char *layout = NULL;
+ size_t count = 0;
+ size_t i;
+
+ switch(device->FmtChans)
+ {
+ case DevFmtMono:
+ channames = mono_names;
+ layout = "mono";
+ count = 1;
+ break;
+ case DevFmtStereo:
+ channames = stereo_names;
+ layout = "stereo";
+ count = 2;
+ break;
+ case DevFmtQuad:
+ channames = quad_names;
+ layout = "quad";
+ count = 4;
+ break;
+ case DevFmtX51:
+ channames = surround51_names;
+ layout = "surround51";
+ count = 6;
+ break;
+ case DevFmtX51Rear:
+ channames = surround51rear_names;
+ layout = "surround51rear";
+ count = 6;
+ break;
+ case DevFmtX61:
+ channames = surround61_names;
+ layout = "surround61";
+ count = 7;
+ break;
+ case DevFmtX71:
+ channames = surround71_names;
+ layout = "surround71";
+ count = 8;
+ 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 = channames[i];
+ char chanlayout[32];
+ const char *value;
+ int props;
+ size_t j;
+
+ 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 %f %f",
+ &chanmap[i].Config.Angle, &chanmap[i].Config.Elevation,
+ &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 channel "SZFMT" properties\n", i);
+ return false;
+ }
+
+ if(strcmp(channame, "front-left") == 0)
+ chanmap[i].ChanName = FrontLeft;
+ else if(strcmp(channame, "front-right") == 0)
+ chanmap[i].ChanName = FrontRight;
+ else if(strcmp(channame, "front-center") == 0)
+ chanmap[i].ChanName = FrontCenter;
+ else if(strcmp(channame, "lfe") == 0)
+ chanmap[i].ChanName = LFE;
+ else if(strcmp(channame, "back-left") == 0)
+ chanmap[i].ChanName = BackLeft;
+ else if(strcmp(channame, "back-right") == 0)
+ chanmap[i].ChanName = BackRight;
+ else if(strcmp(channame, "back-center") == 0)
+ chanmap[i].ChanName = BackCenter;
+ else if(strcmp(channame, "side-left") == 0)
+ chanmap[i].ChanName = SideLeft;
+ else if(strcmp(channame, "side-right") == 0)
+ chanmap[i].ChanName = SideRight;
+
+ if(chanmap[i].ChanName == LFE && props < 22)
+ {
+ if(props > 1 || chanmap[i].Config.Angle != 0.0f)
+ WARN("Unexpected elements for LFE channel\n");
+ chanmap[i].Config.Angle = 0.0f;
+ chanmap[i].Config.Elevation = 0.0f;
+ for(j = 0;j < MAX_AMBI_COEFFS;j++)
+ chanmap[i].Config.HOACoeff[j] = 0.0f;
+ for(j = 0;j < 4;j++)
+ chanmap[i].Config.FOACoeff[j] = 0.0f;
+ }
+ else if(props < 22)
+ {
+ ERR("Failed to parse channel %s elements (expected 22, got %d\n", channame, props);
+ return false;
+ }
+ else
+ {
+ if(!(chanmap[i].Config.Angle >= -180.0f && chanmap[i].Config.Angle <= 180.0f))
+ {
+ ERR("Channel %s angle is out of range (%f not within -180...+180 degrees)\n", channame, chanmap[i].Config.Angle);
+ return false;
+ }
+ chanmap[i].Config.Angle = DEG2RAD(chanmap[i].Config.Angle);
+
+ if(!(chanmap[i].Config.Elevation >= -180.0f && chanmap[i].Config.Elevation <= 180.0f))
+ {
+ ERR("Channel %s elevation is out of range (%f not within -180...+180 degrees)\n", channame, chanmap[i].Config.Angle);
+ return false;
+ }
+ chanmap[i].Config.Elevation = DEG2RAD(chanmap[i].Config.Elevation);
+ }
+ }
+
+ for(i = 0;i < MAX_OUTPUT_CHANNELS && device->ChannelName[i] != InvalidChannel;i++)
+ {
+ size_t j;
+ 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 channel "SZFMT" (label %d) in config\n", i, device->ChannelName[i]);
+ }
+ device->NumChannels = i;
+ return true;
+}
+
ALvoid aluInitPanning(ALCdevice *device)
{
static const ChannelMap MonoCfg[1] = {
@@ -159,6 +342,9 @@ ALvoid aluInitPanning(ALCdevice *device)
memset(device->Channel, 0, sizeof(device->Channel));
device->NumChannels = 0;
+ if(LoadChannelSetup(device))
+ return;
+
switch(device->FmtChans)
{
case DevFmtMono: