SDL: alsa: Map 7.1 audio channels to match what Windows and macOS expect.

From ce11caa80f026f615afbc7c6700638a3552cc122 Mon Sep 17 00:00:00 2001
From: "Ryan C. Gordon" <[EMAIL REDACTED]>
Date: Tue, 21 Sep 2021 16:41:29 -0400
Subject: [PATCH] alsa: Map 7.1 audio channels to match what Windows and macOS
 expect.

This matches what we did a long time ago for 5.1 audio.

Fixes #55.

(FIFTY FIVE. Bug reported 15 years, 3 months, and 11 days ago! lol)
---
 src/audio/alsa/SDL_alsa_audio.c | 68 ++++++++++++++++++++++++++-------
 1 file changed, 54 insertions(+), 14 deletions(-)

diff --git a/src/audio/alsa/SDL_alsa_audio.c b/src/audio/alsa/SDL_alsa_audio.c
index d343efc4a0..1ab7299214 100644
--- a/src/audio/alsa/SDL_alsa_audio.c
+++ b/src/audio/alsa/SDL_alsa_audio.c
@@ -289,12 +289,46 @@ static void swizzle_alsa_channels_6_##T(void *buffer, const Uint32 bufferlen) {
     } \
 }
 
-SWIZ6(Uint64)
-SWIZ6(Uint32)
-SWIZ6(Uint16)
-SWIZ6(Uint8)
 
+/* !!! FIXME: is there a channel swizzler in alsalib instead? */
+/* !!! FIXME: this screams for a SIMD shuffle operation. */
+/*
+ * https://docs.microsoft.com/en-us/windows-hardware/drivers/audio/mapping-stream-formats-to-speaker-configurations
+ * For Linux ALSA, this appears to be FL-FR-RL-RR-C-LFE-SL-SR
+ *  and for Windows DirectX [and CoreAudio], this is FL-FR-C-LFE-SL-SR-RL-RR"
+ */
+#define SWIZ8(T) \
+static void swizzle_alsa_channels_8_##T(void *buffer, const Uint32 bufferlen) { \
+    T *ptr = (T *) buffer; \
+    Uint32 i; \
+    for (i = 0; i < bufferlen; i++, ptr += 6) { \
+        const T center = ptr[2]; \
+        const T subwoofer = ptr[3]; \
+        const T side_left = ptr[4]; \
+        const T side_right = ptr[5]; \
+        const T rear_left = ptr[6]; \
+        const T rear_right = ptr[7]; \
+        ptr[2] = rear_left; \
+        ptr[3] = rear_right; \
+        ptr[4] = center; \
+        ptr[5] = subwoofer; \
+        ptr[6] = side_left; \
+        ptr[7] = side_right; \
+    } \
+}
+
+#define CHANNEL_SWIZZLE(x) \
+    x(Uint64) \
+    x(Uint32) \
+    x(Uint16) \
+    x(Uint8)
+
+CHANNEL_SWIZZLE(SWIZ6)
+CHANNEL_SWIZZLE(SWIZ8)
+
+#undef CHANNEL_SWIZZLE
 #undef SWIZ6
+#undef SWIZ8
 
 
 /*
@@ -304,17 +338,23 @@ SWIZ6(Uint8)
 static void
 swizzle_alsa_channels(_THIS, void *buffer, Uint32 bufferlen)
 {
-    if (this->spec.channels == 6) {
-        switch (SDL_AUDIO_BITSIZE(this->spec.format)) {
-            case 8: swizzle_alsa_channels_6_Uint8(buffer, bufferlen); break;
-            case 16: swizzle_alsa_channels_6_Uint16(buffer, bufferlen); break;
-            case 32: swizzle_alsa_channels_6_Uint32(buffer, bufferlen); break;
-            case 64: swizzle_alsa_channels_6_Uint64(buffer, bufferlen); break;
-            default: SDL_assert(!"unhandled bitsize"); break;
-        }
-    }
+    switch (this->spec.channels) {
+        #define CHANSWIZ(chans) \
+        case chans: \
+            switch ((this->spec.format & (0xFF))) { \
+                case 8: swizzle_alsa_channels_##chans##_Uint8(buffer, bufferlen); break; \
+                case 16: swizzle_alsa_channels_##chans##_Uint16(buffer, bufferlen); break; \
+                case 32: swizzle_alsa_channels_##chans##_Uint32(buffer, bufferlen); break; \
+                case 64: swizzle_alsa_channels_##chans##_Uint64(buffer, bufferlen); break; \
+                default: SDL_assert(!"unhandled bitsize"); break; \
+            } \
+            return;
 
-    /* !!! FIXME: update this for 7.1 if needed, later. */
+        CHANSWIZ(6);
+        CHANSWIZ(8);
+        #undef CHANSWIZ
+        default: break;
+    }
 }
 
 #ifdef SND_CHMAP_API_VERSION