From bd0144065a343c936b6a12be6e546e114575217b Mon Sep 17 00:00:00 2001
From: Chris Robinson <chris.kcat@gmail.com>
Date: Mon, 15 Jun 2020 18:50:59 -0700
Subject: Set channel labels from WFX channel masks

---
 alc/backends/base.cpp | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 55 insertions(+)

(limited to 'alc/backends/base.cpp')

diff --git a/alc/backends/base.cpp b/alc/backends/base.cpp
index 45a1c25d..5c53e3b8 100644
--- a/alc/backends/base.cpp
+++ b/alc/backends/base.cpp
@@ -6,12 +6,20 @@
 #include <atomic>
 #include <thread>
 
+#ifdef _WIN32
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <mmreg.h>
+#endif
+
 #include "AL/al.h"
 
 #include "alcmain.h"
 #include "alexcpt.h"
 #include "alnumeric.h"
+#include "aloptional.h"
 #include "atomic.h"
+#include "logging.h"
 
 
 bool BackendBase::reset()
@@ -140,3 +148,50 @@ void BackendBase::setDefaultChannelOrder()
         break;
     }
 }
+
+#ifdef _WIN32
+void BackendBase::setChannelOrderFromWFXMask(ALuint chanmask)
+{
+    auto get_channel = [](const DWORD chanbit) noexcept -> al::optional<Channel>
+    {
+        switch(chanbit)
+        {
+        case SPEAKER_FRONT_LEFT: return al::make_optional(FrontLeft);
+        case SPEAKER_FRONT_RIGHT: return al::make_optional(FrontRight);
+        case SPEAKER_FRONT_CENTER: return al::make_optional(FrontCenter);
+        case SPEAKER_LOW_FREQUENCY: return al::make_optional(LFE);
+        case SPEAKER_BACK_LEFT: return al::make_optional(BackLeft);
+        case SPEAKER_BACK_RIGHT: return al::make_optional(BackRight);
+        case SPEAKER_FRONT_LEFT_OF_CENTER: break;
+        case SPEAKER_FRONT_RIGHT_OF_CENTER: break;
+        case SPEAKER_BACK_CENTER: return al::make_optional(BackCenter);
+        case SPEAKER_SIDE_LEFT: return al::make_optional(SideLeft);
+        case SPEAKER_SIDE_RIGHT: return al::make_optional(SideRight);
+        case SPEAKER_TOP_CENTER: return al::make_optional(TopCenter);
+        case SPEAKER_TOP_FRONT_LEFT: return al::make_optional(TopFrontLeft);
+        case SPEAKER_TOP_FRONT_CENTER: return al::make_optional(TopFrontCenter);
+        case SPEAKER_TOP_FRONT_RIGHT: return al::make_optional(TopFrontRight);
+        case SPEAKER_TOP_BACK_LEFT: return al::make_optional(TopBackLeft);
+        case SPEAKER_TOP_BACK_CENTER: return al::make_optional(TopBackCenter);
+        case SPEAKER_TOP_BACK_RIGHT: return al::make_optional(TopBackRight);
+        }
+        WARN("Unhandled WFX channel bit 0x%lx\n", chanbit);
+        return al::nullopt;
+    };
+
+    const ALuint numchans{mDevice->channelsFromFmt()};
+    ALuint idx{0};
+    while(chanmask)
+    {
+        const int bit{CTZ32(chanmask)};
+        const ALuint mask{1u << bit};
+        chanmask &= ~mask;
+
+        if(auto label = get_channel(mask))
+        {
+            mDevice->RealOut.ChannelIndex[*label] = idx;
+            if(++idx == numchans) break;
+        }
+    }
+}
+#endif
-- 
cgit v1.2.3