Quellcode durchsuchen

audio: Generate the channel converter code from a program.

Ryan C. Gordon vor 2 Jahren
Ursprung
Commit
49ec8db5f8
3 geänderte Dateien mit 1911 neuen und 1153 gelöschten Zeilen
  1. 450 0
      build-scripts/gen_audio_channel_conversion.c
  2. 1459 0
      src/audio/SDL_audio_channel_converters.h
  3. 2 1153
      src/audio/SDL_audiocvt.c

+ 450 - 0
build-scripts/gen_audio_channel_conversion.c

@@ -0,0 +1,450 @@
+/*
+  Simple DirectMedia Layer
+  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+*/
+
+#include <stdio.h>
+
+/*
+
+Built with:
+
+gcc -o genchancvt build-scripts/gen_audio_channel_conversion.c -lm && ./genchancvt > src/audio/SDL_audio_channel_converters.h
+
+*/
+
+#define NUM_CHANNELS 8
+
+static const char *layout_names[NUM_CHANNELS] = {
+    "Mono", "Stereo", "2.1", "Quad", "4.1", "5.1", "6.1", "7.1"
+};
+
+static const char *channel_names[NUM_CHANNELS][NUM_CHANNELS] = {
+    /* mono */   { "FC" },
+    /* stereo */ { "FL", "FR" },
+    /* 2.1 */    { "FL", "FR", "LFE" },
+    /* quad */   { "FL", "FR", "BL", "BR" },
+    /* 4.1 */    { "FL", "FR", "LFE", "BL", "BR" },
+    /* 5.1 */    { "FL", "FR", "FC", "LFE", "BL", "BR" },
+    /* 6.1 */    { "FL", "FR", "FC", "LFE", "BC", "SL", "SR" },
+    /* 7.1 */    { "FL", "FR", "FC", "LFE", "BL", "BR", "SL", "SR" },
+};
+
+
+/*
+ * This table is from FAudio:
+ *
+ *  https://raw.githubusercontent.com/FNA-XNA/FAudio/master/src/matrix_defaults.inl
+ */
+static const float channel_conversion_matrix[8][8][64] = {
+{
+	/* 1 x 1 */
+	{ 1.000000000f },
+	/* 1 x 2 */
+	{ 1.000000000f, 1.000000000f },
+	/* 1 x 3 */
+	{ 1.000000000f, 1.000000000f, 0.000000000f },
+	/* 1 x 4 */
+	{ 1.000000000f, 1.000000000f, 0.000000000f, 0.000000000f },
+	/* 1 x 5 */
+	{ 1.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f },
+	/* 1 x 6 */
+	{ 1.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f },
+	/* 1 x 7 */
+	{ 1.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f },
+	/* 1 x 8 */
+	{ 1.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f }
+},
+{
+	/* 2 x 1 */
+	{ 0.500000000f, 0.500000000f },
+	/* 2 x 2 */
+	{ 1.000000000f, 0.000000000f, 0.000000000f, 1.000000000f },
+	/* 2 x 3 */
+	{ 1.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f },
+	/* 2 x 4 */
+	{ 1.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f },
+	/* 2 x 5 */
+	{ 1.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f },
+	/* 2 x 6 */
+	{ 1.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f },
+	/* 2 x 7 */
+	{ 1.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f },
+	/* 2 x 8 */
+	{ 1.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f }
+},
+{
+	/* 3 x 1 */
+	{ 0.333333343f, 0.333333343f, 0.333333343f },
+	/* 3 x 2 */
+	{ 0.800000012f, 0.000000000f, 0.200000003f, 0.000000000f, 0.800000012f, 0.200000003f },
+	/* 3 x 3 */
+	{ 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f },
+	/* 3 x 4 */
+	{ 0.888888896f, 0.000000000f, 0.111111112f, 0.000000000f, 0.888888896f, 0.111111112f, 0.000000000f, 0.000000000f, 0.111111112f, 0.000000000f, 0.000000000f, 0.111111112f },
+	/* 3 x 5 */
+	{ 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f },
+	/* 3 x 6 */
+	{ 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f },
+	/* 3 x 7 */
+	{ 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f },
+	/* 3 x 8 */
+	{ 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f }
+},
+{
+	/* 4 x 1 */
+	{ 0.250000000f, 0.250000000f, 0.250000000f, 0.250000000f },
+	/* 4 x 2 */
+	{ 0.421000004f, 0.000000000f, 0.358999997f, 0.219999999f, 0.000000000f, 0.421000004f, 0.219999999f, 0.358999997f },
+	/* 4 x 3 */
+	{ 0.421000004f, 0.000000000f, 0.358999997f, 0.219999999f, 0.000000000f, 0.421000004f, 0.219999999f, 0.358999997f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f },
+	/* 4 x 4 */
+	{ 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f },
+	/* 4 x 5 */
+	{ 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f },
+	/* 4 x 6 */
+	{ 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f },
+	/* 4 x 7 */
+	{ 0.939999998f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.939999998f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.500000000f, 0.500000000f, 0.000000000f, 0.000000000f, 0.796000004f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.796000004f },
+	/* 4 x 8 */
+	{ 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f }
+},
+{
+	/* 5 x 1 */
+	{ 0.200000003f, 0.200000003f, 0.200000003f, 0.200000003f, 0.200000003f },
+	/* 5 x 2 */
+	{ 0.374222219f, 0.000000000f, 0.111111112f, 0.319111109f, 0.195555553f, 0.000000000f, 0.374222219f, 0.111111112f, 0.195555553f, 0.319111109f },
+	/* 5 x 3 */
+	{ 0.421000004f, 0.000000000f, 0.000000000f, 0.358999997f, 0.219999999f, 0.000000000f, 0.421000004f, 0.000000000f, 0.219999999f, 0.358999997f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f },
+	/* 5 x 4 */
+	{ 0.941176474f, 0.000000000f, 0.058823530f, 0.000000000f, 0.000000000f, 0.000000000f, 0.941176474f, 0.058823530f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.058823530f, 0.941176474f, 0.000000000f, 0.000000000f, 0.000000000f, 0.058823530f, 0.000000000f, 0.941176474f },
+	/* 5 x 5 */
+	{ 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f },
+	/* 5 x 6 */
+	{ 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f },
+	/* 5 x 7 */
+	{ 0.939999998f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.939999998f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.500000000f, 0.500000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.796000004f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.796000004f },
+	/* 5 x 8 */
+	{ 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f }
+},
+{
+	/* 6 x 1 */
+	{ 0.166666672f, 0.166666672f, 0.166666672f, 0.166666672f, 0.166666672f, 0.166666672f },
+	/* 6 x 2 */
+	{ 0.294545442f, 0.000000000f, 0.208181813f, 0.090909094f, 0.251818180f, 0.154545456f, 0.000000000f, 0.294545442f, 0.208181813f, 0.090909094f, 0.154545456f, 0.251818180f },
+	/* 6 x 3 */
+	{ 0.324000001f, 0.000000000f, 0.229000002f, 0.000000000f, 0.277000010f, 0.170000002f, 0.000000000f, 0.324000001f, 0.229000002f, 0.000000000f, 0.170000002f, 0.277000010f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f },
+	/* 6 x 4 */
+	{ 0.558095276f, 0.000000000f, 0.394285709f, 0.047619049f, 0.000000000f, 0.000000000f, 0.000000000f, 0.558095276f, 0.394285709f, 0.047619049f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.047619049f, 0.558095276f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.047619049f, 0.000000000f, 0.558095276f },
+	/* 6 x 5 */
+	{ 0.586000025f, 0.000000000f, 0.414000005f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.586000025f, 0.414000005f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.586000025f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.586000025f },
+	/* 6 x 6 */
+	{ 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f },
+	/* 6 x 7 */
+	{ 0.939999998f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.939999998f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.939999998f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.500000000f, 0.500000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.796000004f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.796000004f },
+	/* 6 x 8 */
+	{ 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f }
+},
+{
+	/* 7 x 1 */
+	{ 0.143142849f, 0.143142849f, 0.143142849f, 0.142857149f, 0.143142849f, 0.143142849f, 0.143142849f },
+	/* 7 x 2 */
+	{ 0.247384623f, 0.000000000f, 0.174461529f, 0.076923080f, 0.174461529f, 0.226153851f, 0.100615382f, 0.000000000f, 0.247384623f, 0.174461529f, 0.076923080f, 0.174461529f, 0.100615382f, 0.226153851f },
+	/* 7 x 3 */
+	{ 0.268000007f, 0.000000000f, 0.188999996f, 0.000000000f, 0.188999996f, 0.245000005f, 0.108999997f, 0.000000000f, 0.268000007f, 0.188999996f, 0.000000000f, 0.188999996f, 0.108999997f, 0.245000005f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f },
+	/* 7 x 4 */
+	{ 0.463679999f, 0.000000000f, 0.327360004f, 0.040000003f, 0.000000000f, 0.168960005f, 0.000000000f, 0.000000000f, 0.463679999f, 0.327360004f, 0.040000003f, 0.000000000f, 0.000000000f, 0.168960005f, 0.000000000f, 0.000000000f, 0.000000000f, 0.040000003f, 0.327360004f, 0.431039989f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.040000003f, 0.327360004f, 0.000000000f, 0.431039989f },
+	/* 7 x 5 */
+	{ 0.483000010f, 0.000000000f, 0.340999991f, 0.000000000f, 0.000000000f, 0.175999999f, 0.000000000f, 0.000000000f, 0.483000010f, 0.340999991f, 0.000000000f, 0.000000000f, 0.000000000f, 0.175999999f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.340999991f, 0.449000001f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.340999991f, 0.000000000f, 0.449000001f },
+	/* 7 x 6 */
+	{ 0.611000001f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.223000005f, 0.000000000f, 0.000000000f, 0.611000001f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.223000005f, 0.000000000f, 0.000000000f, 0.611000001f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.432000011f, 0.568000019f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.432000011f, 0.000000000f, 0.568000019f },
+	/* 7 x 7 */
+	{ 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f },
+	/* 7 x 8 */
+	{ 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.707000017f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.707000017f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f }
+},
+{
+	/* 8 x 1 */
+	{ 0.125125006f, 0.125125006f, 0.125125006f, 0.125000000f, 0.125125006f, 0.125125006f, 0.125125006f, 0.125125006f },
+	/* 8 x 2 */
+	{ 0.211866662f, 0.000000000f, 0.150266662f, 0.066666670f, 0.181066677f, 0.111066669f, 0.194133341f, 0.085866667f, 0.000000000f, 0.211866662f, 0.150266662f, 0.066666670f, 0.111066669f, 0.181066677f, 0.085866667f, 0.194133341f },
+	/* 8 x 3 */
+	{ 0.226999998f, 0.000000000f, 0.160999998f, 0.000000000f, 0.194000006f, 0.119000003f, 0.208000004f, 0.092000000f, 0.000000000f, 0.226999998f, 0.160999998f, 0.000000000f, 0.119000003f, 0.194000006f, 0.092000000f, 0.208000004f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f },
+	/* 8 x 4 */
+	{ 0.466344833f, 0.000000000f, 0.329241365f, 0.034482758f, 0.000000000f, 0.000000000f, 0.169931039f, 0.000000000f, 0.000000000f, 0.466344833f, 0.329241365f, 0.034482758f, 0.000000000f, 0.000000000f, 0.000000000f, 0.169931039f, 0.000000000f, 0.000000000f, 0.000000000f, 0.034482758f, 0.466344833f, 0.000000000f, 0.433517247f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.034482758f, 0.000000000f, 0.466344833f, 0.000000000f, 0.433517247f },
+	/* 8 x 5 */
+	{ 0.483000010f, 0.000000000f, 0.340999991f, 0.000000000f, 0.000000000f, 0.000000000f, 0.175999999f, 0.000000000f, 0.000000000f, 0.483000010f, 0.340999991f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.175999999f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.483000010f, 0.000000000f, 0.449000001f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.483000010f, 0.000000000f, 0.449000001f },
+	/* 8 x 6 */
+	{ 0.518000007f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.188999996f, 0.000000000f, 0.000000000f, 0.518000007f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.188999996f, 0.000000000f, 0.000000000f, 0.518000007f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.518000007f, 0.000000000f, 0.481999993f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.518000007f, 0.000000000f, 0.481999993f },
+	/* 8 x 7 */
+	{ 0.541000009f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.541000009f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.541000009f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.287999988f, 0.287999988f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.458999991f, 0.000000000f, 0.541000009f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.458999991f, 0.000000000f, 0.541000009f },
+	/* 8 x 8 */
+	{ 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f }
+}
+};
+
+static char *remove_dots(const char *str)  /* this is NOT robust. */
+{
+    static char retval1[32];
+    static char retval2[32];
+    static int idx = 0;
+    char *retval = (idx++ & 1) ? retval1 : retval2;
+    char *ptr = retval;
+    while (*str) {
+        if (*str != '.') {
+            *(ptr++) = *str;
+        }
+        str++;
+    }
+    *ptr = '\0';
+    return retval;
+}
+
+static char *lowercase(const char *str)  /* this is NOT robust. */
+{
+    static char retval1[32];
+    static char retval2[32];
+    static int idx = 0;
+    char *retval = (idx++ & 1) ? retval1 : retval2;
+    char *ptr = retval;
+    while (*str) {
+        const char ch = *(str++);
+        *(ptr++) = ((ch >= 'A') && (ch <= 'Z')) ? (ch - ('A' - 'a')) : ch;
+    }
+    *ptr = '\0';
+    return retval;
+}
+
+static void write_converter(const int fromchans, const int tochans)
+{
+    const char *fromstr = layout_names[fromchans-1];
+    const char *tostr = layout_names[tochans-1];
+    const float *cvtmatrix = channel_conversion_matrix[fromchans-1][tochans-1];
+    const float *fptr;
+    const int convert_backwards = (tochans > fromchans);
+    int input_channel_used[NUM_CHANNELS];
+    int i, j;
+
+    if (tochans == fromchans) {
+        return;  /* nothing to convert, don't generate a converter. */
+    }
+
+    for (i = 0; i < fromchans; i++) {
+        input_channel_used[i] = 0;
+    }
+
+    fptr = cvtmatrix;
+    for (j = 0; j < tochans; j++) {
+        for (i = 0; i < fromchans; i++) {
+            #if 0
+            printf("to=%d, from=%d, coeff=%f\n", j, i, *fptr);
+            #endif
+            if (*(fptr++) != 0.0f) {
+                input_channel_used[i]++;
+            }
+        }
+    }
+
+    printf("static void SDLCALL\n"
+           "SDL_Convert%sTo%s(SDL_AudioCVT *cvt, SDL_AudioFormat format)\n"
+           "{\n", remove_dots(fromstr), remove_dots(tostr));
+
+    if (convert_backwards) {  /* must convert backwards when growing the output in-place. */
+        printf("    float *dst = ((float *) (cvt->buf + ((cvt->len_cvt / %d) * %d)));\n", fromchans, tochans - 1);
+        printf("    const float *src = ((const float *) (cvt->buf + cvt->len_cvt)) - %d;\n", fromchans);
+    } else {
+        printf("    float *dst = (float *) cvt->buf;\n");
+        printf("    const float *src = dst;\n");
+    }
+
+    printf("    int i;\n"
+           "\n"
+           "    LOG_DEBUG_CONVERT(\"%s\", \"%s\");\n"
+           "    SDL_assert(format == AUDIO_F32SYS);\n"
+           "\n", lowercase(fromstr), lowercase(tostr));
+
+    if (convert_backwards) {
+        printf("    /* convert backwards, since output is growing in-place. */\n");
+        printf("    for (i = cvt->len_cvt / (sizeof (float) * %d); i; i--, src -= %d, dst -= %d) {\n", fromchans, fromchans, tochans);
+        fptr = cvtmatrix;
+        for (i = 0; i < fromchans; i++) {
+            if (input_channel_used[i] > 1) {  /* don't read it from src more than once. */
+                printf("        const float src%s = src[%d];\n", channel_names[fromchans-1][i], i);
+            }
+        }
+
+        for (j = tochans - 1; j >= 0; j--) {
+            int has_input = 0;
+            fptr = cvtmatrix + (fromchans * j);
+            printf("        dst[%d] /* %s */ =", j, channel_names[tochans-1][j]);
+            for (i = fromchans - 1; i >= 0; i--) {
+                const float coefficient = fptr[i];
+                char srcname[32];
+                if (coefficient == 0.0f) {
+                    continue;
+                } else if (input_channel_used[i] > 1) {
+                    snprintf(srcname, sizeof (srcname), "src%s", channel_names[fromchans-1][i]);
+                } else {
+                    snprintf(srcname, sizeof (srcname), "src[%d]", i);
+                }
+
+                if (has_input) {
+                    printf(" +");
+                }
+
+                has_input = 1;
+
+                if (coefficient == 1.0f) {
+                    printf(" %s", srcname);
+                } else {
+                    printf(" (%s * %.9ff)", srcname, coefficient);
+                }
+            }
+
+            if (!has_input) {
+                printf(" 0.0f");
+            }
+
+            printf(";\n");
+        }
+
+        printf("    }\n");
+    } else {
+        printf("    for (i = cvt->len_cvt / (sizeof (float) * %d); i; i--, src += %d, dst += %d) {\n", fromchans, fromchans, tochans);
+
+        fptr = cvtmatrix;
+        for (i = 0; i < fromchans; i++) {
+            if (input_channel_used[i] > 1) {  /* don't read it from src more than once. */
+                printf("        const float src%s = src[%d];\n", channel_names[fromchans-1][i], i);
+            }
+        }
+
+        for (j = 0; j < tochans; j++) {
+            int has_input = 0;
+            fptr = cvtmatrix + (fromchans * j);
+            printf("        dst[%d] /* %s */ =", j, channel_names[tochans-1][j]);
+            for (i = 0; i < fromchans; i++) {
+                const float coefficient = fptr[i];
+                char srcname[32];
+                if (coefficient == 0.0f) {
+                    continue;
+                } else if (input_channel_used[i] > 1) {
+                    snprintf(srcname, sizeof (srcname), "src%s", channel_names[fromchans-1][i]);
+                } else {
+                    snprintf(srcname, sizeof (srcname), "src[%d]", i);
+                }
+
+                if (has_input) {
+                    printf(" +");
+                }
+
+                has_input = 1;
+
+                if (coefficient == 1.0f) {
+                    printf(" %s", srcname);
+                } else {
+                    printf(" (%s * %.9ff)", srcname, coefficient);
+                }
+            }
+
+            if (!has_input) {
+                printf(" 0.0f");
+            }
+
+            printf(";\n");
+        }
+        printf("    }\n");
+    }
+
+    printf("\n");
+
+    if ((fromchans > 1) && (tochans > 1)) {
+        printf("    cvt->len_cvt = (cvt->len_cvt / %d) * %d;\n", fromchans, tochans);
+    } else if (tochans == 1) {
+        printf("    cvt->len_cvt = cvt->len_cvt / %d;\n", fromchans);
+    } else /* if (fromchans == 1) */ {
+        printf("    cvt->len_cvt = cvt->len_cvt * %d;\n", tochans);
+    }
+
+    printf("    if (cvt->filters[++cvt->filter_index]) {\n"
+           "        cvt->filters[cvt->filter_index] (cvt, format);\n"
+           "    }\n"
+           "}\n\n");
+}
+
+int main(void)
+{
+    int ini, outi;
+
+    printf(
+        "/*\n"
+        "  Simple DirectMedia Layer\n"
+        "  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>\n"
+        "\n"
+        "  This software is provided 'as-is', without any express or implied\n"
+        "  warranty.  In no event will the authors be held liable for any damages\n"
+        "  arising from the use of this software.\n"
+        "\n"
+        "  Permission is granted to anyone to use this software for any purpose,\n"
+        "  including commercial applications, and to alter it and redistribute it\n"
+        "  freely, subject to the following restrictions:\n"
+        "\n"
+        "  1. The origin of this software must not be misrepresented; you must not\n"
+        "     claim that you wrote the original software. If you use this software\n"
+        "     in a product, an acknowledgment in the product documentation would be\n"
+        "     appreciated but is not required.\n"
+        "  2. Altered source versions must be plainly marked as such, and must not be\n"
+        "     misrepresented as being the original software.\n"
+        "  3. This notice may not be removed or altered from any source distribution.\n"
+        "*/\n"
+        "\n"
+        "/* DO NOT EDIT, THIS FILE WAS GENERATED BY build-scripts/gen_audio_channel_conversion.c */\n"
+        "\n"
+    );
+
+    for (ini = 1; ini <= NUM_CHANNELS; ini++) {
+        for (outi = 1; outi <= NUM_CHANNELS; outi++) {
+            write_converter(ini, outi);
+        }
+    }
+
+    printf("static const SDL_AudioFilter channel_converters[%d][%d] = {   /* [from][to] */\n", NUM_CHANNELS, NUM_CHANNELS);
+    for (ini = 1; ini <= NUM_CHANNELS; ini++) {
+        const char *comma = "";
+        printf("    {");
+        for (outi = 1; outi <= NUM_CHANNELS; outi++) {
+            const char *fromstr = layout_names[ini-1];
+            const char *tostr = layout_names[outi-1];
+            if (ini == outi) {
+                printf("%s NULL", comma);
+            } else {
+                printf("%s SDL_Convert%sTo%s", comma, remove_dots(fromstr), remove_dots(tostr));
+            }
+            comma = ",";
+        }
+        printf(" }%s\n", (ini == NUM_CHANNELS) ? "" : ",");
+    }
+
+    printf("};\n\n");
+    printf("/* vi: set ts=4 sw=4 expandtab: */\n\n");
+
+    return 0;
+}
+
+/* vi: set ts=4 sw=4 expandtab: */

+ 1459 - 0
src/audio/SDL_audio_channel_converters.h

@@ -0,0 +1,1459 @@
+/*
+  Simple DirectMedia Layer
+  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+*/
+
+/* DO NOT EDIT, THIS FILE WAS GENERATED BY build-scripts/gen_audio_channel_conversion.c */
+
+static void SDLCALL
+SDL_ConvertMonoToStereo(SDL_AudioCVT *cvt, SDL_AudioFormat format)
+{
+    float *dst = ((float *) (cvt->buf + ((cvt->len_cvt / 1) * 1)));
+    const float *src = ((const float *) (cvt->buf + cvt->len_cvt)) - 1;
+    int i;
+
+    LOG_DEBUG_CONVERT("mono", "stereo");
+    SDL_assert(format == AUDIO_F32SYS);
+
+    /* convert backwards, since output is growing in-place. */
+    for (i = cvt->len_cvt / (sizeof (float) * 1); i; i--, src -= 1, dst -= 2) {
+        const float srcFC = src[0];
+        dst[1] /* FR */ = srcFC;
+        dst[0] /* FL */ = srcFC;
+    }
+
+    cvt->len_cvt = cvt->len_cvt * 2;
+    if (cvt->filters[++cvt->filter_index]) {
+        cvt->filters[cvt->filter_index] (cvt, format);
+    }
+}
+
+static void SDLCALL
+SDL_ConvertMonoTo21(SDL_AudioCVT *cvt, SDL_AudioFormat format)
+{
+    float *dst = ((float *) (cvt->buf + ((cvt->len_cvt / 1) * 2)));
+    const float *src = ((const float *) (cvt->buf + cvt->len_cvt)) - 1;
+    int i;
+
+    LOG_DEBUG_CONVERT("mono", "2.1");
+    SDL_assert(format == AUDIO_F32SYS);
+
+    /* convert backwards, since output is growing in-place. */
+    for (i = cvt->len_cvt / (sizeof (float) * 1); i; i--, src -= 1, dst -= 3) {
+        const float srcFC = src[0];
+        dst[2] /* LFE */ = 0.0f;
+        dst[1] /* FR */ = srcFC;
+        dst[0] /* FL */ = srcFC;
+    }
+
+    cvt->len_cvt = cvt->len_cvt * 3;
+    if (cvt->filters[++cvt->filter_index]) {
+        cvt->filters[cvt->filter_index] (cvt, format);
+    }
+}
+
+static void SDLCALL
+SDL_ConvertMonoToQuad(SDL_AudioCVT *cvt, SDL_AudioFormat format)
+{
+    float *dst = ((float *) (cvt->buf + ((cvt->len_cvt / 1) * 3)));
+    const float *src = ((const float *) (cvt->buf + cvt->len_cvt)) - 1;
+    int i;
+
+    LOG_DEBUG_CONVERT("mono", "quad");
+    SDL_assert(format == AUDIO_F32SYS);
+
+    /* convert backwards, since output is growing in-place. */
+    for (i = cvt->len_cvt / (sizeof (float) * 1); i; i--, src -= 1, dst -= 4) {
+        const float srcFC = src[0];
+        dst[3] /* BR */ = 0.0f;
+        dst[2] /* BL */ = 0.0f;
+        dst[1] /* FR */ = srcFC;
+        dst[0] /* FL */ = srcFC;
+    }
+
+    cvt->len_cvt = cvt->len_cvt * 4;
+    if (cvt->filters[++cvt->filter_index]) {
+        cvt->filters[cvt->filter_index] (cvt, format);
+    }
+}
+
+static void SDLCALL
+SDL_ConvertMonoTo41(SDL_AudioCVT *cvt, SDL_AudioFormat format)
+{
+    float *dst = ((float *) (cvt->buf + ((cvt->len_cvt / 1) * 4)));
+    const float *src = ((const float *) (cvt->buf + cvt->len_cvt)) - 1;
+    int i;
+
+    LOG_DEBUG_CONVERT("mono", "4.1");
+    SDL_assert(format == AUDIO_F32SYS);
+
+    /* convert backwards, since output is growing in-place. */
+    for (i = cvt->len_cvt / (sizeof (float) * 1); i; i--, src -= 1, dst -= 5) {
+        const float srcFC = src[0];
+        dst[4] /* BR */ = 0.0f;
+        dst[3] /* BL */ = 0.0f;
+        dst[2] /* LFE */ = 0.0f;
+        dst[1] /* FR */ = srcFC;
+        dst[0] /* FL */ = srcFC;
+    }
+
+    cvt->len_cvt = cvt->len_cvt * 5;
+    if (cvt->filters[++cvt->filter_index]) {
+        cvt->filters[cvt->filter_index] (cvt, format);
+    }
+}
+
+static void SDLCALL
+SDL_ConvertMonoTo51(SDL_AudioCVT *cvt, SDL_AudioFormat format)
+{
+    float *dst = ((float *) (cvt->buf + ((cvt->len_cvt / 1) * 5)));
+    const float *src = ((const float *) (cvt->buf + cvt->len_cvt)) - 1;
+    int i;
+
+    LOG_DEBUG_CONVERT("mono", "5.1");
+    SDL_assert(format == AUDIO_F32SYS);
+
+    /* convert backwards, since output is growing in-place. */
+    for (i = cvt->len_cvt / (sizeof (float) * 1); i; i--, src -= 1, dst -= 6) {
+        const float srcFC = src[0];
+        dst[5] /* BR */ = 0.0f;
+        dst[4] /* BL */ = 0.0f;
+        dst[3] /* LFE */ = 0.0f;
+        dst[2] /* FC */ = 0.0f;
+        dst[1] /* FR */ = srcFC;
+        dst[0] /* FL */ = srcFC;
+    }
+
+    cvt->len_cvt = cvt->len_cvt * 6;
+    if (cvt->filters[++cvt->filter_index]) {
+        cvt->filters[cvt->filter_index] (cvt, format);
+    }
+}
+
+static void SDLCALL
+SDL_ConvertMonoTo61(SDL_AudioCVT *cvt, SDL_AudioFormat format)
+{
+    float *dst = ((float *) (cvt->buf + ((cvt->len_cvt / 1) * 6)));
+    const float *src = ((const float *) (cvt->buf + cvt->len_cvt)) - 1;
+    int i;
+
+    LOG_DEBUG_CONVERT("mono", "6.1");
+    SDL_assert(format == AUDIO_F32SYS);
+
+    /* convert backwards, since output is growing in-place. */
+    for (i = cvt->len_cvt / (sizeof (float) * 1); i; i--, src -= 1, dst -= 7) {
+        const float srcFC = src[0];
+        dst[6] /* SR */ = 0.0f;
+        dst[5] /* SL */ = 0.0f;
+        dst[4] /* BC */ = 0.0f;
+        dst[3] /* LFE */ = 0.0f;
+        dst[2] /* FC */ = 0.0f;
+        dst[1] /* FR */ = srcFC;
+        dst[0] /* FL */ = srcFC;
+    }
+
+    cvt->len_cvt = cvt->len_cvt * 7;
+    if (cvt->filters[++cvt->filter_index]) {
+        cvt->filters[cvt->filter_index] (cvt, format);
+    }
+}
+
+static void SDLCALL
+SDL_ConvertMonoTo71(SDL_AudioCVT *cvt, SDL_AudioFormat format)
+{
+    float *dst = ((float *) (cvt->buf + ((cvt->len_cvt / 1) * 7)));
+    const float *src = ((const float *) (cvt->buf + cvt->len_cvt)) - 1;
+    int i;
+
+    LOG_DEBUG_CONVERT("mono", "7.1");
+    SDL_assert(format == AUDIO_F32SYS);
+
+    /* convert backwards, since output is growing in-place. */
+    for (i = cvt->len_cvt / (sizeof (float) * 1); i; i--, src -= 1, dst -= 8) {
+        const float srcFC = src[0];
+        dst[7] /* SR */ = 0.0f;
+        dst[6] /* SL */ = 0.0f;
+        dst[5] /* BR */ = 0.0f;
+        dst[4] /* BL */ = 0.0f;
+        dst[3] /* LFE */ = 0.0f;
+        dst[2] /* FC */ = 0.0f;
+        dst[1] /* FR */ = srcFC;
+        dst[0] /* FL */ = srcFC;
+    }
+
+    cvt->len_cvt = cvt->len_cvt * 8;
+    if (cvt->filters[++cvt->filter_index]) {
+        cvt->filters[cvt->filter_index] (cvt, format);
+    }
+}
+
+static void SDLCALL
+SDL_ConvertStereoToMono(SDL_AudioCVT *cvt, SDL_AudioFormat format)
+{
+    float *dst = (float *) cvt->buf;
+    const float *src = dst;
+    int i;
+
+    LOG_DEBUG_CONVERT("stereo", "mono");
+    SDL_assert(format == AUDIO_F32SYS);
+
+    for (i = cvt->len_cvt / (sizeof (float) * 2); i; i--, src += 2, dst += 1) {
+        dst[0] /* FC */ = (src[0] * 0.500000000f) + (src[1] * 0.500000000f);
+    }
+
+    cvt->len_cvt = cvt->len_cvt / 2;
+    if (cvt->filters[++cvt->filter_index]) {
+        cvt->filters[cvt->filter_index] (cvt, format);
+    }
+}
+
+static void SDLCALL
+SDL_ConvertStereoTo21(SDL_AudioCVT *cvt, SDL_AudioFormat format)
+{
+    float *dst = ((float *) (cvt->buf + ((cvt->len_cvt / 2) * 2)));
+    const float *src = ((const float *) (cvt->buf + cvt->len_cvt)) - 2;
+    int i;
+
+    LOG_DEBUG_CONVERT("stereo", "2.1");
+    SDL_assert(format == AUDIO_F32SYS);
+
+    /* convert backwards, since output is growing in-place. */
+    for (i = cvt->len_cvt / (sizeof (float) * 2); i; i--, src -= 2, dst -= 3) {
+        dst[2] /* LFE */ = 0.0f;
+        dst[1] /* FR */ = src[1];
+        dst[0] /* FL */ = src[0];
+    }
+
+    cvt->len_cvt = (cvt->len_cvt / 2) * 3;
+    if (cvt->filters[++cvt->filter_index]) {
+        cvt->filters[cvt->filter_index] (cvt, format);
+    }
+}
+
+static void SDLCALL
+SDL_ConvertStereoToQuad(SDL_AudioCVT *cvt, SDL_AudioFormat format)
+{
+    float *dst = ((float *) (cvt->buf + ((cvt->len_cvt / 2) * 3)));
+    const float *src = ((const float *) (cvt->buf + cvt->len_cvt)) - 2;
+    int i;
+
+    LOG_DEBUG_CONVERT("stereo", "quad");
+    SDL_assert(format == AUDIO_F32SYS);
+
+    /* convert backwards, since output is growing in-place. */
+    for (i = cvt->len_cvt / (sizeof (float) * 2); i; i--, src -= 2, dst -= 4) {
+        dst[3] /* BR */ = 0.0f;
+        dst[2] /* BL */ = 0.0f;
+        dst[1] /* FR */ = src[1];
+        dst[0] /* FL */ = src[0];
+    }
+
+    cvt->len_cvt = (cvt->len_cvt / 2) * 4;
+    if (cvt->filters[++cvt->filter_index]) {
+        cvt->filters[cvt->filter_index] (cvt, format);
+    }
+}
+
+static void SDLCALL
+SDL_ConvertStereoTo41(SDL_AudioCVT *cvt, SDL_AudioFormat format)
+{
+    float *dst = ((float *) (cvt->buf + ((cvt->len_cvt / 2) * 4)));
+    const float *src = ((const float *) (cvt->buf + cvt->len_cvt)) - 2;
+    int i;
+
+    LOG_DEBUG_CONVERT("stereo", "4.1");
+    SDL_assert(format == AUDIO_F32SYS);
+
+    /* convert backwards, since output is growing in-place. */
+    for (i = cvt->len_cvt / (sizeof (float) * 2); i; i--, src -= 2, dst -= 5) {
+        dst[4] /* BR */ = 0.0f;
+        dst[3] /* BL */ = 0.0f;
+        dst[2] /* LFE */ = 0.0f;
+        dst[1] /* FR */ = src[1];
+        dst[0] /* FL */ = src[0];
+    }
+
+    cvt->len_cvt = (cvt->len_cvt / 2) * 5;
+    if (cvt->filters[++cvt->filter_index]) {
+        cvt->filters[cvt->filter_index] (cvt, format);
+    }
+}
+
+static void SDLCALL
+SDL_ConvertStereoTo51(SDL_AudioCVT *cvt, SDL_AudioFormat format)
+{
+    float *dst = ((float *) (cvt->buf + ((cvt->len_cvt / 2) * 5)));
+    const float *src = ((const float *) (cvt->buf + cvt->len_cvt)) - 2;
+    int i;
+
+    LOG_DEBUG_CONVERT("stereo", "5.1");
+    SDL_assert(format == AUDIO_F32SYS);
+
+    /* convert backwards, since output is growing in-place. */
+    for (i = cvt->len_cvt / (sizeof (float) * 2); i; i--, src -= 2, dst -= 6) {
+        dst[5] /* BR */ = 0.0f;
+        dst[4] /* BL */ = 0.0f;
+        dst[3] /* LFE */ = 0.0f;
+        dst[2] /* FC */ = 0.0f;
+        dst[1] /* FR */ = src[1];
+        dst[0] /* FL */ = src[0];
+    }
+
+    cvt->len_cvt = (cvt->len_cvt / 2) * 6;
+    if (cvt->filters[++cvt->filter_index]) {
+        cvt->filters[cvt->filter_index] (cvt, format);
+    }
+}
+
+static void SDLCALL
+SDL_ConvertStereoTo61(SDL_AudioCVT *cvt, SDL_AudioFormat format)
+{
+    float *dst = ((float *) (cvt->buf + ((cvt->len_cvt / 2) * 6)));
+    const float *src = ((const float *) (cvt->buf + cvt->len_cvt)) - 2;
+    int i;
+
+    LOG_DEBUG_CONVERT("stereo", "6.1");
+    SDL_assert(format == AUDIO_F32SYS);
+
+    /* convert backwards, since output is growing in-place. */
+    for (i = cvt->len_cvt / (sizeof (float) * 2); i; i--, src -= 2, dst -= 7) {
+        dst[6] /* SR */ = 0.0f;
+        dst[5] /* SL */ = 0.0f;
+        dst[4] /* BC */ = 0.0f;
+        dst[3] /* LFE */ = 0.0f;
+        dst[2] /* FC */ = 0.0f;
+        dst[1] /* FR */ = src[1];
+        dst[0] /* FL */ = src[0];
+    }
+
+    cvt->len_cvt = (cvt->len_cvt / 2) * 7;
+    if (cvt->filters[++cvt->filter_index]) {
+        cvt->filters[cvt->filter_index] (cvt, format);
+    }
+}
+
+static void SDLCALL
+SDL_ConvertStereoTo71(SDL_AudioCVT *cvt, SDL_AudioFormat format)
+{
+    float *dst = ((float *) (cvt->buf + ((cvt->len_cvt / 2) * 7)));
+    const float *src = ((const float *) (cvt->buf + cvt->len_cvt)) - 2;
+    int i;
+
+    LOG_DEBUG_CONVERT("stereo", "7.1");
+    SDL_assert(format == AUDIO_F32SYS);
+
+    /* convert backwards, since output is growing in-place. */
+    for (i = cvt->len_cvt / (sizeof (float) * 2); i; i--, src -= 2, dst -= 8) {
+        dst[7] /* SR */ = 0.0f;
+        dst[6] /* SL */ = 0.0f;
+        dst[5] /* BR */ = 0.0f;
+        dst[4] /* BL */ = 0.0f;
+        dst[3] /* LFE */ = 0.0f;
+        dst[2] /* FC */ = 0.0f;
+        dst[1] /* FR */ = src[1];
+        dst[0] /* FL */ = src[0];
+    }
+
+    cvt->len_cvt = (cvt->len_cvt / 2) * 8;
+    if (cvt->filters[++cvt->filter_index]) {
+        cvt->filters[cvt->filter_index] (cvt, format);
+    }
+}
+
+static void SDLCALL
+SDL_Convert21ToMono(SDL_AudioCVT *cvt, SDL_AudioFormat format)
+{
+    float *dst = (float *) cvt->buf;
+    const float *src = dst;
+    int i;
+
+    LOG_DEBUG_CONVERT("2.1", "mono");
+    SDL_assert(format == AUDIO_F32SYS);
+
+    for (i = cvt->len_cvt / (sizeof (float) * 3); i; i--, src += 3, dst += 1) {
+        dst[0] /* FC */ = (src[0] * 0.333333343f) + (src[1] * 0.333333343f) + (src[2] * 0.333333343f);
+    }
+
+    cvt->len_cvt = cvt->len_cvt / 3;
+    if (cvt->filters[++cvt->filter_index]) {
+        cvt->filters[cvt->filter_index] (cvt, format);
+    }
+}
+
+static void SDLCALL
+SDL_Convert21ToStereo(SDL_AudioCVT *cvt, SDL_AudioFormat format)
+{
+    float *dst = (float *) cvt->buf;
+    const float *src = dst;
+    int i;
+
+    LOG_DEBUG_CONVERT("2.1", "stereo");
+    SDL_assert(format == AUDIO_F32SYS);
+
+    for (i = cvt->len_cvt / (sizeof (float) * 3); i; i--, src += 3, dst += 2) {
+        const float srcLFE = src[2];
+        dst[0] /* FL */ = (src[0] * 0.800000012f) + (srcLFE * 0.200000003f);
+        dst[1] /* FR */ = (src[1] * 0.800000012f) + (srcLFE * 0.200000003f);
+    }
+
+    cvt->len_cvt = (cvt->len_cvt / 3) * 2;
+    if (cvt->filters[++cvt->filter_index]) {
+        cvt->filters[cvt->filter_index] (cvt, format);
+    }
+}
+
+static void SDLCALL
+SDL_Convert21ToQuad(SDL_AudioCVT *cvt, SDL_AudioFormat format)
+{
+    float *dst = ((float *) (cvt->buf + ((cvt->len_cvt / 3) * 3)));
+    const float *src = ((const float *) (cvt->buf + cvt->len_cvt)) - 3;
+    int i;
+
+    LOG_DEBUG_CONVERT("2.1", "quad");
+    SDL_assert(format == AUDIO_F32SYS);
+
+    /* convert backwards, since output is growing in-place. */
+    for (i = cvt->len_cvt / (sizeof (float) * 3); i; i--, src -= 3, dst -= 4) {
+        const float srcLFE = src[2];
+        dst[3] /* BR */ = (srcLFE * 0.111111112f);
+        dst[2] /* BL */ = (srcLFE * 0.111111112f);
+        dst[1] /* FR */ = (srcLFE * 0.111111112f) + (src[1] * 0.888888896f);
+        dst[0] /* FL */ = (srcLFE * 0.111111112f) + (src[0] * 0.888888896f);
+    }
+
+    cvt->len_cvt = (cvt->len_cvt / 3) * 4;
+    if (cvt->filters[++cvt->filter_index]) {
+        cvt->filters[cvt->filter_index] (cvt, format);
+    }
+}
+
+static void SDLCALL
+SDL_Convert21To41(SDL_AudioCVT *cvt, SDL_AudioFormat format)
+{
+    float *dst = ((float *) (cvt->buf + ((cvt->len_cvt / 3) * 4)));
+    const float *src = ((const float *) (cvt->buf + cvt->len_cvt)) - 3;
+    int i;
+
+    LOG_DEBUG_CONVERT("2.1", "4.1");
+    SDL_assert(format == AUDIO_F32SYS);
+
+    /* convert backwards, since output is growing in-place. */
+    for (i = cvt->len_cvt / (sizeof (float) * 3); i; i--, src -= 3, dst -= 5) {
+        dst[4] /* BR */ = 0.0f;
+        dst[3] /* BL */ = 0.0f;
+        dst[2] /* LFE */ = src[2];
+        dst[1] /* FR */ = src[1];
+        dst[0] /* FL */ = src[0];
+    }
+
+    cvt->len_cvt = (cvt->len_cvt / 3) * 5;
+    if (cvt->filters[++cvt->filter_index]) {
+        cvt->filters[cvt->filter_index] (cvt, format);
+    }
+}
+
+static void SDLCALL
+SDL_Convert21To51(SDL_AudioCVT *cvt, SDL_AudioFormat format)
+{
+    float *dst = ((float *) (cvt->buf + ((cvt->len_cvt / 3) * 5)));
+    const float *src = ((const float *) (cvt->buf + cvt->len_cvt)) - 3;
+    int i;
+
+    LOG_DEBUG_CONVERT("2.1", "5.1");
+    SDL_assert(format == AUDIO_F32SYS);
+
+    /* convert backwards, since output is growing in-place. */
+    for (i = cvt->len_cvt / (sizeof (float) * 3); i; i--, src -= 3, dst -= 6) {
+        dst[5] /* BR */ = 0.0f;
+        dst[4] /* BL */ = 0.0f;
+        dst[3] /* LFE */ = src[2];
+        dst[2] /* FC */ = 0.0f;
+        dst[1] /* FR */ = src[1];
+        dst[0] /* FL */ = src[0];
+    }
+
+    cvt->len_cvt = (cvt->len_cvt / 3) * 6;
+    if (cvt->filters[++cvt->filter_index]) {
+        cvt->filters[cvt->filter_index] (cvt, format);
+    }
+}
+
+static void SDLCALL
+SDL_Convert21To61(SDL_AudioCVT *cvt, SDL_AudioFormat format)
+{
+    float *dst = ((float *) (cvt->buf + ((cvt->len_cvt / 3) * 6)));
+    const float *src = ((const float *) (cvt->buf + cvt->len_cvt)) - 3;
+    int i;
+
+    LOG_DEBUG_CONVERT("2.1", "6.1");
+    SDL_assert(format == AUDIO_F32SYS);
+
+    /* convert backwards, since output is growing in-place. */
+    for (i = cvt->len_cvt / (sizeof (float) * 3); i; i--, src -= 3, dst -= 7) {
+        dst[6] /* SR */ = 0.0f;
+        dst[5] /* SL */ = 0.0f;
+        dst[4] /* BC */ = 0.0f;
+        dst[3] /* LFE */ = src[2];
+        dst[2] /* FC */ = 0.0f;
+        dst[1] /* FR */ = src[1];
+        dst[0] /* FL */ = src[0];
+    }
+
+    cvt->len_cvt = (cvt->len_cvt / 3) * 7;
+    if (cvt->filters[++cvt->filter_index]) {
+        cvt->filters[cvt->filter_index] (cvt, format);
+    }
+}
+
+static void SDLCALL
+SDL_Convert21To71(SDL_AudioCVT *cvt, SDL_AudioFormat format)
+{
+    float *dst = ((float *) (cvt->buf + ((cvt->len_cvt / 3) * 7)));
+    const float *src = ((const float *) (cvt->buf + cvt->len_cvt)) - 3;
+    int i;
+
+    LOG_DEBUG_CONVERT("2.1", "7.1");
+    SDL_assert(format == AUDIO_F32SYS);
+
+    /* convert backwards, since output is growing in-place. */
+    for (i = cvt->len_cvt / (sizeof (float) * 3); i; i--, src -= 3, dst -= 8) {
+        dst[7] /* SR */ = 0.0f;
+        dst[6] /* SL */ = 0.0f;
+        dst[5] /* BR */ = 0.0f;
+        dst[4] /* BL */ = 0.0f;
+        dst[3] /* LFE */ = src[2];
+        dst[2] /* FC */ = 0.0f;
+        dst[1] /* FR */ = src[1];
+        dst[0] /* FL */ = src[0];
+    }
+
+    cvt->len_cvt = (cvt->len_cvt / 3) * 8;
+    if (cvt->filters[++cvt->filter_index]) {
+        cvt->filters[cvt->filter_index] (cvt, format);
+    }
+}
+
+static void SDLCALL
+SDL_ConvertQuadToMono(SDL_AudioCVT *cvt, SDL_AudioFormat format)
+{
+    float *dst = (float *) cvt->buf;
+    const float *src = dst;
+    int i;
+
+    LOG_DEBUG_CONVERT("quad", "mono");
+    SDL_assert(format == AUDIO_F32SYS);
+
+    for (i = cvt->len_cvt / (sizeof (float) * 4); i; i--, src += 4, dst += 1) {
+        dst[0] /* FC */ = (src[0] * 0.250000000f) + (src[1] * 0.250000000f) + (src[2] * 0.250000000f) + (src[3] * 0.250000000f);
+    }
+
+    cvt->len_cvt = cvt->len_cvt / 4;
+    if (cvt->filters[++cvt->filter_index]) {
+        cvt->filters[cvt->filter_index] (cvt, format);
+    }
+}
+
+static void SDLCALL
+SDL_ConvertQuadToStereo(SDL_AudioCVT *cvt, SDL_AudioFormat format)
+{
+    float *dst = (float *) cvt->buf;
+    const float *src = dst;
+    int i;
+
+    LOG_DEBUG_CONVERT("quad", "stereo");
+    SDL_assert(format == AUDIO_F32SYS);
+
+    for (i = cvt->len_cvt / (sizeof (float) * 4); i; i--, src += 4, dst += 2) {
+        const float srcBL = src[2];
+        const float srcBR = src[3];
+        dst[0] /* FL */ = (src[0] * 0.421000004f) + (srcBL * 0.358999997f) + (srcBR * 0.219999999f);
+        dst[1] /* FR */ = (src[1] * 0.421000004f) + (srcBL * 0.219999999f) + (srcBR * 0.358999997f);
+    }
+
+    cvt->len_cvt = (cvt->len_cvt / 4) * 2;
+    if (cvt->filters[++cvt->filter_index]) {
+        cvt->filters[cvt->filter_index] (cvt, format);
+    }
+}
+
+static void SDLCALL
+SDL_ConvertQuadTo21(SDL_AudioCVT *cvt, SDL_AudioFormat format)
+{
+    float *dst = (float *) cvt->buf;
+    const float *src = dst;
+    int i;
+
+    LOG_DEBUG_CONVERT("quad", "2.1");
+    SDL_assert(format == AUDIO_F32SYS);
+
+    for (i = cvt->len_cvt / (sizeof (float) * 4); i; i--, src += 4, dst += 3) {
+        const float srcBL = src[2];
+        const float srcBR = src[3];
+        dst[0] /* FL */ = (src[0] * 0.421000004f) + (srcBL * 0.358999997f) + (srcBR * 0.219999999f);
+        dst[1] /* FR */ = (src[1] * 0.421000004f) + (srcBL * 0.219999999f) + (srcBR * 0.358999997f);
+        dst[2] /* LFE */ = 0.0f;
+    }
+
+    cvt->len_cvt = (cvt->len_cvt / 4) * 3;
+    if (cvt->filters[++cvt->filter_index]) {
+        cvt->filters[cvt->filter_index] (cvt, format);
+    }
+}
+
+static void SDLCALL
+SDL_ConvertQuadTo41(SDL_AudioCVT *cvt, SDL_AudioFormat format)
+{
+    float *dst = ((float *) (cvt->buf + ((cvt->len_cvt / 4) * 4)));
+    const float *src = ((const float *) (cvt->buf + cvt->len_cvt)) - 4;
+    int i;
+
+    LOG_DEBUG_CONVERT("quad", "4.1");
+    SDL_assert(format == AUDIO_F32SYS);
+
+    /* convert backwards, since output is growing in-place. */
+    for (i = cvt->len_cvt / (sizeof (float) * 4); i; i--, src -= 4, dst -= 5) {
+        dst[4] /* BR */ = src[3];
+        dst[3] /* BL */ = src[2];
+        dst[2] /* LFE */ = 0.0f;
+        dst[1] /* FR */ = src[1];
+        dst[0] /* FL */ = src[0];
+    }
+
+    cvt->len_cvt = (cvt->len_cvt / 4) * 5;
+    if (cvt->filters[++cvt->filter_index]) {
+        cvt->filters[cvt->filter_index] (cvt, format);
+    }
+}
+
+static void SDLCALL
+SDL_ConvertQuadTo51(SDL_AudioCVT *cvt, SDL_AudioFormat format)
+{
+    float *dst = ((float *) (cvt->buf + ((cvt->len_cvt / 4) * 5)));
+    const float *src = ((const float *) (cvt->buf + cvt->len_cvt)) - 4;
+    int i;
+
+    LOG_DEBUG_CONVERT("quad", "5.1");
+    SDL_assert(format == AUDIO_F32SYS);
+
+    /* convert backwards, since output is growing in-place. */
+    for (i = cvt->len_cvt / (sizeof (float) * 4); i; i--, src -= 4, dst -= 6) {
+        dst[5] /* BR */ = src[3];
+        dst[4] /* BL */ = src[2];
+        dst[3] /* LFE */ = 0.0f;
+        dst[2] /* FC */ = 0.0f;
+        dst[1] /* FR */ = src[1];
+        dst[0] /* FL */ = src[0];
+    }
+
+    cvt->len_cvt = (cvt->len_cvt / 4) * 6;
+    if (cvt->filters[++cvt->filter_index]) {
+        cvt->filters[cvt->filter_index] (cvt, format);
+    }
+}
+
+static void SDLCALL
+SDL_ConvertQuadTo61(SDL_AudioCVT *cvt, SDL_AudioFormat format)
+{
+    float *dst = ((float *) (cvt->buf + ((cvt->len_cvt / 4) * 6)));
+    const float *src = ((const float *) (cvt->buf + cvt->len_cvt)) - 4;
+    int i;
+
+    LOG_DEBUG_CONVERT("quad", "6.1");
+    SDL_assert(format == AUDIO_F32SYS);
+
+    /* convert backwards, since output is growing in-place. */
+    for (i = cvt->len_cvt / (sizeof (float) * 4); i; i--, src -= 4, dst -= 7) {
+        const float srcBL = src[2];
+        const float srcBR = src[3];
+        dst[6] /* SR */ = (srcBR * 0.796000004f);
+        dst[5] /* SL */ = (srcBL * 0.796000004f);
+        dst[4] /* BC */ = (srcBR * 0.500000000f) + (srcBL * 0.500000000f);
+        dst[3] /* LFE */ = 0.0f;
+        dst[2] /* FC */ = 0.0f;
+        dst[1] /* FR */ = (src[1] * 0.939999998f);
+        dst[0] /* FL */ = (src[0] * 0.939999998f);
+    }
+
+    cvt->len_cvt = (cvt->len_cvt / 4) * 7;
+    if (cvt->filters[++cvt->filter_index]) {
+        cvt->filters[cvt->filter_index] (cvt, format);
+    }
+}
+
+static void SDLCALL
+SDL_ConvertQuadTo71(SDL_AudioCVT *cvt, SDL_AudioFormat format)
+{
+    float *dst = ((float *) (cvt->buf + ((cvt->len_cvt / 4) * 7)));
+    const float *src = ((const float *) (cvt->buf + cvt->len_cvt)) - 4;
+    int i;
+
+    LOG_DEBUG_CONVERT("quad", "7.1");
+    SDL_assert(format == AUDIO_F32SYS);
+
+    /* convert backwards, since output is growing in-place. */
+    for (i = cvt->len_cvt / (sizeof (float) * 4); i; i--, src -= 4, dst -= 8) {
+        dst[7] /* SR */ = 0.0f;
+        dst[6] /* SL */ = 0.0f;
+        dst[5] /* BR */ = src[3];
+        dst[4] /* BL */ = src[2];
+        dst[3] /* LFE */ = 0.0f;
+        dst[2] /* FC */ = 0.0f;
+        dst[1] /* FR */ = src[1];
+        dst[0] /* FL */ = src[0];
+    }
+
+    cvt->len_cvt = (cvt->len_cvt / 4) * 8;
+    if (cvt->filters[++cvt->filter_index]) {
+        cvt->filters[cvt->filter_index] (cvt, format);
+    }
+}
+
+static void SDLCALL
+SDL_Convert41ToMono(SDL_AudioCVT *cvt, SDL_AudioFormat format)
+{
+    float *dst = (float *) cvt->buf;
+    const float *src = dst;
+    int i;
+
+    LOG_DEBUG_CONVERT("4.1", "mono");
+    SDL_assert(format == AUDIO_F32SYS);
+
+    for (i = cvt->len_cvt / (sizeof (float) * 5); i; i--, src += 5, dst += 1) {
+        dst[0] /* FC */ = (src[0] * 0.200000003f) + (src[1] * 0.200000003f) + (src[2] * 0.200000003f) + (src[3] * 0.200000003f) + (src[4] * 0.200000003f);
+    }
+
+    cvt->len_cvt = cvt->len_cvt / 5;
+    if (cvt->filters[++cvt->filter_index]) {
+        cvt->filters[cvt->filter_index] (cvt, format);
+    }
+}
+
+static void SDLCALL
+SDL_Convert41ToStereo(SDL_AudioCVT *cvt, SDL_AudioFormat format)
+{
+    float *dst = (float *) cvt->buf;
+    const float *src = dst;
+    int i;
+
+    LOG_DEBUG_CONVERT("4.1", "stereo");
+    SDL_assert(format == AUDIO_F32SYS);
+
+    for (i = cvt->len_cvt / (sizeof (float) * 5); i; i--, src += 5, dst += 2) {
+        const float srcLFE = src[2];
+        const float srcBL = src[3];
+        const float srcBR = src[4];
+        dst[0] /* FL */ = (src[0] * 0.374222219f) + (srcLFE * 0.111111112f) + (srcBL * 0.319111109f) + (srcBR * 0.195555553f);
+        dst[1] /* FR */ = (src[1] * 0.374222219f) + (srcLFE * 0.111111112f) + (srcBL * 0.195555553f) + (srcBR * 0.319111109f);
+    }
+
+    cvt->len_cvt = (cvt->len_cvt / 5) * 2;
+    if (cvt->filters[++cvt->filter_index]) {
+        cvt->filters[cvt->filter_index] (cvt, format);
+    }
+}
+
+static void SDLCALL
+SDL_Convert41To21(SDL_AudioCVT *cvt, SDL_AudioFormat format)
+{
+    float *dst = (float *) cvt->buf;
+    const float *src = dst;
+    int i;
+
+    LOG_DEBUG_CONVERT("4.1", "2.1");
+    SDL_assert(format == AUDIO_F32SYS);
+
+    for (i = cvt->len_cvt / (sizeof (float) * 5); i; i--, src += 5, dst += 3) {
+        const float srcBL = src[3];
+        const float srcBR = src[4];
+        dst[0] /* FL */ = (src[0] * 0.421000004f) + (srcBL * 0.358999997f) + (srcBR * 0.219999999f);
+        dst[1] /* FR */ = (src[1] * 0.421000004f) + (srcBL * 0.219999999f) + (srcBR * 0.358999997f);
+        dst[2] /* LFE */ = src[2];
+    }
+
+    cvt->len_cvt = (cvt->len_cvt / 5) * 3;
+    if (cvt->filters[++cvt->filter_index]) {
+        cvt->filters[cvt->filter_index] (cvt, format);
+    }
+}
+
+static void SDLCALL
+SDL_Convert41ToQuad(SDL_AudioCVT *cvt, SDL_AudioFormat format)
+{
+    float *dst = (float *) cvt->buf;
+    const float *src = dst;
+    int i;
+
+    LOG_DEBUG_CONVERT("4.1", "quad");
+    SDL_assert(format == AUDIO_F32SYS);
+
+    for (i = cvt->len_cvt / (sizeof (float) * 5); i; i--, src += 5, dst += 4) {
+        const float srcLFE = src[2];
+        dst[0] /* FL */ = (src[0] * 0.941176474f) + (srcLFE * 0.058823530f);
+        dst[1] /* FR */ = (src[1] * 0.941176474f) + (srcLFE * 0.058823530f);
+        dst[2] /* BL */ = (srcLFE * 0.058823530f) + (src[3] * 0.941176474f);
+        dst[3] /* BR */ = (srcLFE * 0.058823530f) + (src[4] * 0.941176474f);
+    }
+
+    cvt->len_cvt = (cvt->len_cvt / 5) * 4;
+    if (cvt->filters[++cvt->filter_index]) {
+        cvt->filters[cvt->filter_index] (cvt, format);
+    }
+}
+
+static void SDLCALL
+SDL_Convert41To51(SDL_AudioCVT *cvt, SDL_AudioFormat format)
+{
+    float *dst = ((float *) (cvt->buf + ((cvt->len_cvt / 5) * 5)));
+    const float *src = ((const float *) (cvt->buf + cvt->len_cvt)) - 5;
+    int i;
+
+    LOG_DEBUG_CONVERT("4.1", "5.1");
+    SDL_assert(format == AUDIO_F32SYS);
+
+    /* convert backwards, since output is growing in-place. */
+    for (i = cvt->len_cvt / (sizeof (float) * 5); i; i--, src -= 5, dst -= 6) {
+        dst[5] /* BR */ = src[4];
+        dst[4] /* BL */ = src[3];
+        dst[3] /* LFE */ = src[2];
+        dst[2] /* FC */ = 0.0f;
+        dst[1] /* FR */ = src[1];
+        dst[0] /* FL */ = src[0];
+    }
+
+    cvt->len_cvt = (cvt->len_cvt / 5) * 6;
+    if (cvt->filters[++cvt->filter_index]) {
+        cvt->filters[cvt->filter_index] (cvt, format);
+    }
+}
+
+static void SDLCALL
+SDL_Convert41To61(SDL_AudioCVT *cvt, SDL_AudioFormat format)
+{
+    float *dst = ((float *) (cvt->buf + ((cvt->len_cvt / 5) * 6)));
+    const float *src = ((const float *) (cvt->buf + cvt->len_cvt)) - 5;
+    int i;
+
+    LOG_DEBUG_CONVERT("4.1", "6.1");
+    SDL_assert(format == AUDIO_F32SYS);
+
+    /* convert backwards, since output is growing in-place. */
+    for (i = cvt->len_cvt / (sizeof (float) * 5); i; i--, src -= 5, dst -= 7) {
+        const float srcBL = src[3];
+        const float srcBR = src[4];
+        dst[6] /* SR */ = (srcBR * 0.796000004f);
+        dst[5] /* SL */ = (srcBL * 0.796000004f);
+        dst[4] /* BC */ = (srcBR * 0.500000000f) + (srcBL * 0.500000000f);
+        dst[3] /* LFE */ = src[2];
+        dst[2] /* FC */ = 0.0f;
+        dst[1] /* FR */ = (src[1] * 0.939999998f);
+        dst[0] /* FL */ = (src[0] * 0.939999998f);
+    }
+
+    cvt->len_cvt = (cvt->len_cvt / 5) * 7;
+    if (cvt->filters[++cvt->filter_index]) {
+        cvt->filters[cvt->filter_index] (cvt, format);
+    }
+}
+
+static void SDLCALL
+SDL_Convert41To71(SDL_AudioCVT *cvt, SDL_AudioFormat format)
+{
+    float *dst = ((float *) (cvt->buf + ((cvt->len_cvt / 5) * 7)));
+    const float *src = ((const float *) (cvt->buf + cvt->len_cvt)) - 5;
+    int i;
+
+    LOG_DEBUG_CONVERT("4.1", "7.1");
+    SDL_assert(format == AUDIO_F32SYS);
+
+    /* convert backwards, since output is growing in-place. */
+    for (i = cvt->len_cvt / (sizeof (float) * 5); i; i--, src -= 5, dst -= 8) {
+        dst[7] /* SR */ = 0.0f;
+        dst[6] /* SL */ = 0.0f;
+        dst[5] /* BR */ = src[4];
+        dst[4] /* BL */ = src[3];
+        dst[3] /* LFE */ = src[2];
+        dst[2] /* FC */ = 0.0f;
+        dst[1] /* FR */ = src[1];
+        dst[0] /* FL */ = src[0];
+    }
+
+    cvt->len_cvt = (cvt->len_cvt / 5) * 8;
+    if (cvt->filters[++cvt->filter_index]) {
+        cvt->filters[cvt->filter_index] (cvt, format);
+    }
+}
+
+static void SDLCALL
+SDL_Convert51ToMono(SDL_AudioCVT *cvt, SDL_AudioFormat format)
+{
+    float *dst = (float *) cvt->buf;
+    const float *src = dst;
+    int i;
+
+    LOG_DEBUG_CONVERT("5.1", "mono");
+    SDL_assert(format == AUDIO_F32SYS);
+
+    for (i = cvt->len_cvt / (sizeof (float) * 6); i; i--, src += 6, dst += 1) {
+        dst[0] /* FC */ = (src[0] * 0.166666672f) + (src[1] * 0.166666672f) + (src[2] * 0.166666672f) + (src[3] * 0.166666672f) + (src[4] * 0.166666672f) + (src[5] * 0.166666672f);
+    }
+
+    cvt->len_cvt = cvt->len_cvt / 6;
+    if (cvt->filters[++cvt->filter_index]) {
+        cvt->filters[cvt->filter_index] (cvt, format);
+    }
+}
+
+static void SDLCALL
+SDL_Convert51ToStereo(SDL_AudioCVT *cvt, SDL_AudioFormat format)
+{
+    float *dst = (float *) cvt->buf;
+    const float *src = dst;
+    int i;
+
+    LOG_DEBUG_CONVERT("5.1", "stereo");
+    SDL_assert(format == AUDIO_F32SYS);
+
+    for (i = cvt->len_cvt / (sizeof (float) * 6); i; i--, src += 6, dst += 2) {
+        const float srcFC = src[2];
+        const float srcLFE = src[3];
+        const float srcBL = src[4];
+        const float srcBR = src[5];
+        dst[0] /* FL */ = (src[0] * 0.294545442f) + (srcFC * 0.208181813f) + (srcLFE * 0.090909094f) + (srcBL * 0.251818180f) + (srcBR * 0.154545456f);
+        dst[1] /* FR */ = (src[1] * 0.294545442f) + (srcFC * 0.208181813f) + (srcLFE * 0.090909094f) + (srcBL * 0.154545456f) + (srcBR * 0.251818180f);
+    }
+
+    cvt->len_cvt = (cvt->len_cvt / 6) * 2;
+    if (cvt->filters[++cvt->filter_index]) {
+        cvt->filters[cvt->filter_index] (cvt, format);
+    }
+}
+
+static void SDLCALL
+SDL_Convert51To21(SDL_AudioCVT *cvt, SDL_AudioFormat format)
+{
+    float *dst = (float *) cvt->buf;
+    const float *src = dst;
+    int i;
+
+    LOG_DEBUG_CONVERT("5.1", "2.1");
+    SDL_assert(format == AUDIO_F32SYS);
+
+    for (i = cvt->len_cvt / (sizeof (float) * 6); i; i--, src += 6, dst += 3) {
+        const float srcFC = src[2];
+        const float srcBL = src[4];
+        const float srcBR = src[5];
+        dst[0] /* FL */ = (src[0] * 0.324000001f) + (srcFC * 0.229000002f) + (srcBL * 0.277000010f) + (srcBR * 0.170000002f);
+        dst[1] /* FR */ = (src[1] * 0.324000001f) + (srcFC * 0.229000002f) + (srcBL * 0.170000002f) + (srcBR * 0.277000010f);
+        dst[2] /* LFE */ = src[3];
+    }
+
+    cvt->len_cvt = (cvt->len_cvt / 6) * 3;
+    if (cvt->filters[++cvt->filter_index]) {
+        cvt->filters[cvt->filter_index] (cvt, format);
+    }
+}
+
+static void SDLCALL
+SDL_Convert51ToQuad(SDL_AudioCVT *cvt, SDL_AudioFormat format)
+{
+    float *dst = (float *) cvt->buf;
+    const float *src = dst;
+    int i;
+
+    LOG_DEBUG_CONVERT("5.1", "quad");
+    SDL_assert(format == AUDIO_F32SYS);
+
+    for (i = cvt->len_cvt / (sizeof (float) * 6); i; i--, src += 6, dst += 4) {
+        const float srcFC = src[2];
+        const float srcLFE = src[3];
+        dst[0] /* FL */ = (src[0] * 0.558095276f) + (srcFC * 0.394285709f) + (srcLFE * 0.047619049f);
+        dst[1] /* FR */ = (src[1] * 0.558095276f) + (srcFC * 0.394285709f) + (srcLFE * 0.047619049f);
+        dst[2] /* BL */ = (srcLFE * 0.047619049f) + (src[4] * 0.558095276f);
+        dst[3] /* BR */ = (srcLFE * 0.047619049f) + (src[5] * 0.558095276f);
+    }
+
+    cvt->len_cvt = (cvt->len_cvt / 6) * 4;
+    if (cvt->filters[++cvt->filter_index]) {
+        cvt->filters[cvt->filter_index] (cvt, format);
+    }
+}
+
+static void SDLCALL
+SDL_Convert51To41(SDL_AudioCVT *cvt, SDL_AudioFormat format)
+{
+    float *dst = (float *) cvt->buf;
+    const float *src = dst;
+    int i;
+
+    LOG_DEBUG_CONVERT("5.1", "4.1");
+    SDL_assert(format == AUDIO_F32SYS);
+
+    for (i = cvt->len_cvt / (sizeof (float) * 6); i; i--, src += 6, dst += 5) {
+        const float srcFC = src[2];
+        dst[0] /* FL */ = (src[0] * 0.586000025f) + (srcFC * 0.414000005f);
+        dst[1] /* FR */ = (src[1] * 0.586000025f) + (srcFC * 0.414000005f);
+        dst[2] /* LFE */ = src[3];
+        dst[3] /* BL */ = (src[4] * 0.586000025f);
+        dst[4] /* BR */ = (src[5] * 0.586000025f);
+    }
+
+    cvt->len_cvt = (cvt->len_cvt / 6) * 5;
+    if (cvt->filters[++cvt->filter_index]) {
+        cvt->filters[cvt->filter_index] (cvt, format);
+    }
+}
+
+static void SDLCALL
+SDL_Convert51To61(SDL_AudioCVT *cvt, SDL_AudioFormat format)
+{
+    float *dst = ((float *) (cvt->buf + ((cvt->len_cvt / 6) * 6)));
+    const float *src = ((const float *) (cvt->buf + cvt->len_cvt)) - 6;
+    int i;
+
+    LOG_DEBUG_CONVERT("5.1", "6.1");
+    SDL_assert(format == AUDIO_F32SYS);
+
+    /* convert backwards, since output is growing in-place. */
+    for (i = cvt->len_cvt / (sizeof (float) * 6); i; i--, src -= 6, dst -= 7) {
+        const float srcBL = src[4];
+        const float srcBR = src[5];
+        dst[6] /* SR */ = (srcBR * 0.796000004f);
+        dst[5] /* SL */ = (srcBL * 0.796000004f);
+        dst[4] /* BC */ = (srcBR * 0.500000000f) + (srcBL * 0.500000000f);
+        dst[3] /* LFE */ = src[3];
+        dst[2] /* FC */ = (src[2] * 0.939999998f);
+        dst[1] /* FR */ = (src[1] * 0.939999998f);
+        dst[0] /* FL */ = (src[0] * 0.939999998f);
+    }
+
+    cvt->len_cvt = (cvt->len_cvt / 6) * 7;
+    if (cvt->filters[++cvt->filter_index]) {
+        cvt->filters[cvt->filter_index] (cvt, format);
+    }
+}
+
+static void SDLCALL
+SDL_Convert51To71(SDL_AudioCVT *cvt, SDL_AudioFormat format)
+{
+    float *dst = ((float *) (cvt->buf + ((cvt->len_cvt / 6) * 7)));
+    const float *src = ((const float *) (cvt->buf + cvt->len_cvt)) - 6;
+    int i;
+
+    LOG_DEBUG_CONVERT("5.1", "7.1");
+    SDL_assert(format == AUDIO_F32SYS);
+
+    /* convert backwards, since output is growing in-place. */
+    for (i = cvt->len_cvt / (sizeof (float) * 6); i; i--, src -= 6, dst -= 8) {
+        dst[7] /* SR */ = 0.0f;
+        dst[6] /* SL */ = 0.0f;
+        dst[5] /* BR */ = src[5];
+        dst[4] /* BL */ = src[4];
+        dst[3] /* LFE */ = src[3];
+        dst[2] /* FC */ = src[2];
+        dst[1] /* FR */ = src[1];
+        dst[0] /* FL */ = src[0];
+    }
+
+    cvt->len_cvt = (cvt->len_cvt / 6) * 8;
+    if (cvt->filters[++cvt->filter_index]) {
+        cvt->filters[cvt->filter_index] (cvt, format);
+    }
+}
+
+static void SDLCALL
+SDL_Convert61ToMono(SDL_AudioCVT *cvt, SDL_AudioFormat format)
+{
+    float *dst = (float *) cvt->buf;
+    const float *src = dst;
+    int i;
+
+    LOG_DEBUG_CONVERT("6.1", "mono");
+    SDL_assert(format == AUDIO_F32SYS);
+
+    for (i = cvt->len_cvt / (sizeof (float) * 7); i; i--, src += 7, dst += 1) {
+        dst[0] /* FC */ = (src[0] * 0.143142849f) + (src[1] * 0.143142849f) + (src[2] * 0.143142849f) + (src[3] * 0.142857149f) + (src[4] * 0.143142849f) + (src[5] * 0.143142849f) + (src[6] * 0.143142849f);
+    }
+
+    cvt->len_cvt = cvt->len_cvt / 7;
+    if (cvt->filters[++cvt->filter_index]) {
+        cvt->filters[cvt->filter_index] (cvt, format);
+    }
+}
+
+static void SDLCALL
+SDL_Convert61ToStereo(SDL_AudioCVT *cvt, SDL_AudioFormat format)
+{
+    float *dst = (float *) cvt->buf;
+    const float *src = dst;
+    int i;
+
+    LOG_DEBUG_CONVERT("6.1", "stereo");
+    SDL_assert(format == AUDIO_F32SYS);
+
+    for (i = cvt->len_cvt / (sizeof (float) * 7); i; i--, src += 7, dst += 2) {
+        const float srcFC = src[2];
+        const float srcLFE = src[3];
+        const float srcBC = src[4];
+        const float srcSL = src[5];
+        const float srcSR = src[6];
+        dst[0] /* FL */ = (src[0] * 0.247384623f) + (srcFC * 0.174461529f) + (srcLFE * 0.076923080f) + (srcBC * 0.174461529f) + (srcSL * 0.226153851f) + (srcSR * 0.100615382f);
+        dst[1] /* FR */ = (src[1] * 0.247384623f) + (srcFC * 0.174461529f) + (srcLFE * 0.076923080f) + (srcBC * 0.174461529f) + (srcSL * 0.100615382f) + (srcSR * 0.226153851f);
+    }
+
+    cvt->len_cvt = (cvt->len_cvt / 7) * 2;
+    if (cvt->filters[++cvt->filter_index]) {
+        cvt->filters[cvt->filter_index] (cvt, format);
+    }
+}
+
+static void SDLCALL
+SDL_Convert61To21(SDL_AudioCVT *cvt, SDL_AudioFormat format)
+{
+    float *dst = (float *) cvt->buf;
+    const float *src = dst;
+    int i;
+
+    LOG_DEBUG_CONVERT("6.1", "2.1");
+    SDL_assert(format == AUDIO_F32SYS);
+
+    for (i = cvt->len_cvt / (sizeof (float) * 7); i; i--, src += 7, dst += 3) {
+        const float srcFC = src[2];
+        const float srcBC = src[4];
+        const float srcSL = src[5];
+        const float srcSR = src[6];
+        dst[0] /* FL */ = (src[0] * 0.268000007f) + (srcFC * 0.188999996f) + (srcBC * 0.188999996f) + (srcSL * 0.245000005f) + (srcSR * 0.108999997f);
+        dst[1] /* FR */ = (src[1] * 0.268000007f) + (srcFC * 0.188999996f) + (srcBC * 0.188999996f) + (srcSL * 0.108999997f) + (srcSR * 0.245000005f);
+        dst[2] /* LFE */ = src[3];
+    }
+
+    cvt->len_cvt = (cvt->len_cvt / 7) * 3;
+    if (cvt->filters[++cvt->filter_index]) {
+        cvt->filters[cvt->filter_index] (cvt, format);
+    }
+}
+
+static void SDLCALL
+SDL_Convert61ToQuad(SDL_AudioCVT *cvt, SDL_AudioFormat format)
+{
+    float *dst = (float *) cvt->buf;
+    const float *src = dst;
+    int i;
+
+    LOG_DEBUG_CONVERT("6.1", "quad");
+    SDL_assert(format == AUDIO_F32SYS);
+
+    for (i = cvt->len_cvt / (sizeof (float) * 7); i; i--, src += 7, dst += 4) {
+        const float srcFC = src[2];
+        const float srcLFE = src[3];
+        const float srcBC = src[4];
+        const float srcSL = src[5];
+        const float srcSR = src[6];
+        dst[0] /* FL */ = (src[0] * 0.463679999f) + (srcFC * 0.327360004f) + (srcLFE * 0.040000003f) + (srcSL * 0.168960005f);
+        dst[1] /* FR */ = (src[1] * 0.463679999f) + (srcFC * 0.327360004f) + (srcLFE * 0.040000003f) + (srcSR * 0.168960005f);
+        dst[2] /* BL */ = (srcLFE * 0.040000003f) + (srcBC * 0.327360004f) + (srcSL * 0.431039989f);
+        dst[3] /* BR */ = (srcLFE * 0.040000003f) + (srcBC * 0.327360004f) + (srcSR * 0.431039989f);
+    }
+
+    cvt->len_cvt = (cvt->len_cvt / 7) * 4;
+    if (cvt->filters[++cvt->filter_index]) {
+        cvt->filters[cvt->filter_index] (cvt, format);
+    }
+}
+
+static void SDLCALL
+SDL_Convert61To41(SDL_AudioCVT *cvt, SDL_AudioFormat format)
+{
+    float *dst = (float *) cvt->buf;
+    const float *src = dst;
+    int i;
+
+    LOG_DEBUG_CONVERT("6.1", "4.1");
+    SDL_assert(format == AUDIO_F32SYS);
+
+    for (i = cvt->len_cvt / (sizeof (float) * 7); i; i--, src += 7, dst += 5) {
+        const float srcFC = src[2];
+        const float srcBC = src[4];
+        const float srcSL = src[5];
+        const float srcSR = src[6];
+        dst[0] /* FL */ = (src[0] * 0.483000010f) + (srcFC * 0.340999991f) + (srcSL * 0.175999999f);
+        dst[1] /* FR */ = (src[1] * 0.483000010f) + (srcFC * 0.340999991f) + (srcSR * 0.175999999f);
+        dst[2] /* LFE */ = src[3];
+        dst[3] /* BL */ = (srcBC * 0.340999991f) + (srcSL * 0.449000001f);
+        dst[4] /* BR */ = (srcBC * 0.340999991f) + (srcSR * 0.449000001f);
+    }
+
+    cvt->len_cvt = (cvt->len_cvt / 7) * 5;
+    if (cvt->filters[++cvt->filter_index]) {
+        cvt->filters[cvt->filter_index] (cvt, format);
+    }
+}
+
+static void SDLCALL
+SDL_Convert61To51(SDL_AudioCVT *cvt, SDL_AudioFormat format)
+{
+    float *dst = (float *) cvt->buf;
+    const float *src = dst;
+    int i;
+
+    LOG_DEBUG_CONVERT("6.1", "5.1");
+    SDL_assert(format == AUDIO_F32SYS);
+
+    for (i = cvt->len_cvt / (sizeof (float) * 7); i; i--, src += 7, dst += 6) {
+        const float srcBC = src[4];
+        const float srcSL = src[5];
+        const float srcSR = src[6];
+        dst[0] /* FL */ = (src[0] * 0.611000001f) + (srcSL * 0.223000005f);
+        dst[1] /* FR */ = (src[1] * 0.611000001f) + (srcSR * 0.223000005f);
+        dst[2] /* FC */ = (src[2] * 0.611000001f);
+        dst[3] /* LFE */ = src[3];
+        dst[4] /* BL */ = (srcBC * 0.432000011f) + (srcSL * 0.568000019f);
+        dst[5] /* BR */ = (srcBC * 0.432000011f) + (srcSR * 0.568000019f);
+    }
+
+    cvt->len_cvt = (cvt->len_cvt / 7) * 6;
+    if (cvt->filters[++cvt->filter_index]) {
+        cvt->filters[cvt->filter_index] (cvt, format);
+    }
+}
+
+static void SDLCALL
+SDL_Convert61To71(SDL_AudioCVT *cvt, SDL_AudioFormat format)
+{
+    float *dst = ((float *) (cvt->buf + ((cvt->len_cvt / 7) * 7)));
+    const float *src = ((const float *) (cvt->buf + cvt->len_cvt)) - 7;
+    int i;
+
+    LOG_DEBUG_CONVERT("6.1", "7.1");
+    SDL_assert(format == AUDIO_F32SYS);
+
+    /* convert backwards, since output is growing in-place. */
+    for (i = cvt->len_cvt / (sizeof (float) * 7); i; i--, src -= 7, dst -= 8) {
+        const float srcBC = src[4];
+        dst[7] /* SR */ = src[6];
+        dst[6] /* SL */ = src[5];
+        dst[5] /* BR */ = (srcBC * 0.707000017f);
+        dst[4] /* BL */ = (srcBC * 0.707000017f);
+        dst[3] /* LFE */ = src[3];
+        dst[2] /* FC */ = src[2];
+        dst[1] /* FR */ = src[1];
+        dst[0] /* FL */ = src[0];
+    }
+
+    cvt->len_cvt = (cvt->len_cvt / 7) * 8;
+    if (cvt->filters[++cvt->filter_index]) {
+        cvt->filters[cvt->filter_index] (cvt, format);
+    }
+}
+
+static void SDLCALL
+SDL_Convert71ToMono(SDL_AudioCVT *cvt, SDL_AudioFormat format)
+{
+    float *dst = (float *) cvt->buf;
+    const float *src = dst;
+    int i;
+
+    LOG_DEBUG_CONVERT("7.1", "mono");
+    SDL_assert(format == AUDIO_F32SYS);
+
+    for (i = cvt->len_cvt / (sizeof (float) * 8); i; i--, src += 8, dst += 1) {
+        dst[0] /* FC */ = (src[0] * 0.125125006f) + (src[1] * 0.125125006f) + (src[2] * 0.125125006f) + (src[3] * 0.125000000f) + (src[4] * 0.125125006f) + (src[5] * 0.125125006f) + (src[6] * 0.125125006f) + (src[7] * 0.125125006f);
+    }
+
+    cvt->len_cvt = cvt->len_cvt / 8;
+    if (cvt->filters[++cvt->filter_index]) {
+        cvt->filters[cvt->filter_index] (cvt, format);
+    }
+}
+
+static void SDLCALL
+SDL_Convert71ToStereo(SDL_AudioCVT *cvt, SDL_AudioFormat format)
+{
+    float *dst = (float *) cvt->buf;
+    const float *src = dst;
+    int i;
+
+    LOG_DEBUG_CONVERT("7.1", "stereo");
+    SDL_assert(format == AUDIO_F32SYS);
+
+    for (i = cvt->len_cvt / (sizeof (float) * 8); i; i--, src += 8, dst += 2) {
+        const float srcFC = src[2];
+        const float srcLFE = src[3];
+        const float srcBL = src[4];
+        const float srcBR = src[5];
+        const float srcSL = src[6];
+        const float srcSR = src[7];
+        dst[0] /* FL */ = (src[0] * 0.211866662f) + (srcFC * 0.150266662f) + (srcLFE * 0.066666670f) + (srcBL * 0.181066677f) + (srcBR * 0.111066669f) + (srcSL * 0.194133341f) + (srcSR * 0.085866667f);
+        dst[1] /* FR */ = (src[1] * 0.211866662f) + (srcFC * 0.150266662f) + (srcLFE * 0.066666670f) + (srcBL * 0.111066669f) + (srcBR * 0.181066677f) + (srcSL * 0.085866667f) + (srcSR * 0.194133341f);
+    }
+
+    cvt->len_cvt = (cvt->len_cvt / 8) * 2;
+    if (cvt->filters[++cvt->filter_index]) {
+        cvt->filters[cvt->filter_index] (cvt, format);
+    }
+}
+
+static void SDLCALL
+SDL_Convert71To21(SDL_AudioCVT *cvt, SDL_AudioFormat format)
+{
+    float *dst = (float *) cvt->buf;
+    const float *src = dst;
+    int i;
+
+    LOG_DEBUG_CONVERT("7.1", "2.1");
+    SDL_assert(format == AUDIO_F32SYS);
+
+    for (i = cvt->len_cvt / (sizeof (float) * 8); i; i--, src += 8, dst += 3) {
+        const float srcFC = src[2];
+        const float srcBL = src[4];
+        const float srcBR = src[5];
+        const float srcSL = src[6];
+        const float srcSR = src[7];
+        dst[0] /* FL */ = (src[0] * 0.226999998f) + (srcFC * 0.160999998f) + (srcBL * 0.194000006f) + (srcBR * 0.119000003f) + (srcSL * 0.208000004f) + (srcSR * 0.092000000f);
+        dst[1] /* FR */ = (src[1] * 0.226999998f) + (srcFC * 0.160999998f) + (srcBL * 0.119000003f) + (srcBR * 0.194000006f) + (srcSL * 0.092000000f) + (srcSR * 0.208000004f);
+        dst[2] /* LFE */ = src[3];
+    }
+
+    cvt->len_cvt = (cvt->len_cvt / 8) * 3;
+    if (cvt->filters[++cvt->filter_index]) {
+        cvt->filters[cvt->filter_index] (cvt, format);
+    }
+}
+
+static void SDLCALL
+SDL_Convert71ToQuad(SDL_AudioCVT *cvt, SDL_AudioFormat format)
+{
+    float *dst = (float *) cvt->buf;
+    const float *src = dst;
+    int i;
+
+    LOG_DEBUG_CONVERT("7.1", "quad");
+    SDL_assert(format == AUDIO_F32SYS);
+
+    for (i = cvt->len_cvt / (sizeof (float) * 8); i; i--, src += 8, dst += 4) {
+        const float srcFC = src[2];
+        const float srcLFE = src[3];
+        const float srcSL = src[6];
+        const float srcSR = src[7];
+        dst[0] /* FL */ = (src[0] * 0.466344833f) + (srcFC * 0.329241365f) + (srcLFE * 0.034482758f) + (srcSL * 0.169931039f);
+        dst[1] /* FR */ = (src[1] * 0.466344833f) + (srcFC * 0.329241365f) + (srcLFE * 0.034482758f) + (srcSR * 0.169931039f);
+        dst[2] /* BL */ = (srcLFE * 0.034482758f) + (src[4] * 0.466344833f) + (srcSL * 0.433517247f);
+        dst[3] /* BR */ = (srcLFE * 0.034482758f) + (src[5] * 0.466344833f) + (srcSR * 0.433517247f);
+    }
+
+    cvt->len_cvt = (cvt->len_cvt / 8) * 4;
+    if (cvt->filters[++cvt->filter_index]) {
+        cvt->filters[cvt->filter_index] (cvt, format);
+    }
+}
+
+static void SDLCALL
+SDL_Convert71To41(SDL_AudioCVT *cvt, SDL_AudioFormat format)
+{
+    float *dst = (float *) cvt->buf;
+    const float *src = dst;
+    int i;
+
+    LOG_DEBUG_CONVERT("7.1", "4.1");
+    SDL_assert(format == AUDIO_F32SYS);
+
+    for (i = cvt->len_cvt / (sizeof (float) * 8); i; i--, src += 8, dst += 5) {
+        const float srcFC = src[2];
+        const float srcSL = src[6];
+        const float srcSR = src[7];
+        dst[0] /* FL */ = (src[0] * 0.483000010f) + (srcFC * 0.340999991f) + (srcSL * 0.175999999f);
+        dst[1] /* FR */ = (src[1] * 0.483000010f) + (srcFC * 0.340999991f) + (srcSR * 0.175999999f);
+        dst[2] /* LFE */ = src[3];
+        dst[3] /* BL */ = (src[4] * 0.483000010f) + (srcSL * 0.449000001f);
+        dst[4] /* BR */ = (src[5] * 0.483000010f) + (srcSR * 0.449000001f);
+    }
+
+    cvt->len_cvt = (cvt->len_cvt / 8) * 5;
+    if (cvt->filters[++cvt->filter_index]) {
+        cvt->filters[cvt->filter_index] (cvt, format);
+    }
+}
+
+static void SDLCALL
+SDL_Convert71To51(SDL_AudioCVT *cvt, SDL_AudioFormat format)
+{
+    float *dst = (float *) cvt->buf;
+    const float *src = dst;
+    int i;
+
+    LOG_DEBUG_CONVERT("7.1", "5.1");
+    SDL_assert(format == AUDIO_F32SYS);
+
+    for (i = cvt->len_cvt / (sizeof (float) * 8); i; i--, src += 8, dst += 6) {
+        const float srcSL = src[6];
+        const float srcSR = src[7];
+        dst[0] /* FL */ = (src[0] * 0.518000007f) + (srcSL * 0.188999996f);
+        dst[1] /* FR */ = (src[1] * 0.518000007f) + (srcSR * 0.188999996f);
+        dst[2] /* FC */ = (src[2] * 0.518000007f);
+        dst[3] /* LFE */ = src[3];
+        dst[4] /* BL */ = (src[4] * 0.518000007f) + (srcSL * 0.481999993f);
+        dst[5] /* BR */ = (src[5] * 0.518000007f) + (srcSR * 0.481999993f);
+    }
+
+    cvt->len_cvt = (cvt->len_cvt / 8) * 6;
+    if (cvt->filters[++cvt->filter_index]) {
+        cvt->filters[cvt->filter_index] (cvt, format);
+    }
+}
+
+static void SDLCALL
+SDL_Convert71To61(SDL_AudioCVT *cvt, SDL_AudioFormat format)
+{
+    float *dst = (float *) cvt->buf;
+    const float *src = dst;
+    int i;
+
+    LOG_DEBUG_CONVERT("7.1", "6.1");
+    SDL_assert(format == AUDIO_F32SYS);
+
+    for (i = cvt->len_cvt / (sizeof (float) * 8); i; i--, src += 8, dst += 7) {
+        const float srcBL = src[4];
+        const float srcBR = src[5];
+        dst[0] /* FL */ = (src[0] * 0.541000009f);
+        dst[1] /* FR */ = (src[1] * 0.541000009f);
+        dst[2] /* FC */ = (src[2] * 0.541000009f);
+        dst[3] /* LFE */ = src[3];
+        dst[4] /* BC */ = (srcBL * 0.287999988f) + (srcBR * 0.287999988f);
+        dst[5] /* SL */ = (srcBL * 0.458999991f) + (src[6] * 0.541000009f);
+        dst[6] /* SR */ = (srcBR * 0.458999991f) + (src[7] * 0.541000009f);
+    }
+
+    cvt->len_cvt = (cvt->len_cvt / 8) * 7;
+    if (cvt->filters[++cvt->filter_index]) {
+        cvt->filters[cvt->filter_index] (cvt, format);
+    }
+}
+
+static const SDL_AudioFilter channel_converters[8][8] = {   /* [from][to] */
+    { NULL, SDL_ConvertMonoToStereo, SDL_ConvertMonoTo21, SDL_ConvertMonoToQuad, SDL_ConvertMonoTo41, SDL_ConvertMonoTo51, SDL_ConvertMonoTo61, SDL_ConvertMonoTo71 },
+    { SDL_ConvertStereoToMono, NULL, SDL_ConvertStereoTo21, SDL_ConvertStereoToQuad, SDL_ConvertStereoTo41, SDL_ConvertStereoTo51, SDL_ConvertStereoTo61, SDL_ConvertStereoTo71 },
+    { SDL_Convert21ToMono, SDL_Convert21ToStereo, NULL, SDL_Convert21ToQuad, SDL_Convert21To41, SDL_Convert21To51, SDL_Convert21To61, SDL_Convert21To71 },
+    { SDL_ConvertQuadToMono, SDL_ConvertQuadToStereo, SDL_ConvertQuadTo21, NULL, SDL_ConvertQuadTo41, SDL_ConvertQuadTo51, SDL_ConvertQuadTo61, SDL_ConvertQuadTo71 },
+    { SDL_Convert41ToMono, SDL_Convert41ToStereo, SDL_Convert41To21, SDL_Convert41ToQuad, NULL, SDL_Convert41To51, SDL_Convert41To61, SDL_Convert41To71 },
+    { SDL_Convert51ToMono, SDL_Convert51ToStereo, SDL_Convert51To21, SDL_Convert51ToQuad, SDL_Convert51To41, NULL, SDL_Convert51To61, SDL_Convert51To71 },
+    { SDL_Convert61ToMono, SDL_Convert61ToStereo, SDL_Convert61To21, SDL_Convert61ToQuad, SDL_Convert61To41, SDL_Convert61To51, NULL, SDL_Convert61To71 },
+    { SDL_Convert71ToMono, SDL_Convert71ToStereo, SDL_Convert71To21, SDL_Convert71ToQuad, SDL_Convert71To41, SDL_Convert71To51, SDL_Convert71To61, NULL }
+};
+
+/* vi: set ts=4 sw=4 expandtab: */
+

+ 2 - 1153
src/audio/SDL_audiocvt.c

@@ -22,9 +22,6 @@
 
 /* Functions for audio drivers to perform runtime conversion of audio format */
 
-/* FIXME: Channel weights when converting from more channels to fewer may need to be adjusted, see https://msdn.microsoft.com/en-us/library/windows/desktop/ff819070(v=vs.85).aspx
-*/
-
 #include "SDL.h"
 #include "SDL_audio.h"
 #include "SDL_audio_c.h"
@@ -286,44 +283,6 @@ SDL_Convert51ToStereo_NEON(SDL_AudioCVT * cvt, SDL_AudioFormat format)
 #endif
 
 
-/* Channel conversion is now mostly following this scheme, borrowed from FNA
-   (which is following the scheme of XNA)...
-   https://github.com/FNA-XNA/FAudio/blob/master/src/matrix_defaults.inl */
-
-/* CONVERT FROM MONO... */
-/* Mono duplicates to stereo and all other channels are silenced. */
-
-#define CVT_MONO_TO(toname, tonamestr, num_channels, zeroingcode) \
-    static void SDLCALL SDL_ConvertMonoTo##toname(SDL_AudioCVT * cvt, SDL_AudioFormat format) { \
-        const float *src = ((const float *) (cvt->buf + cvt->len_cvt)) - 1; \
-        float *dst = ((float *) (cvt->buf + cvt->len_cvt * num_channels)) - num_channels; \
-        int i; \
-        LOG_DEBUG_CONVERT("mono", tonamestr); \
-        SDL_assert(format == AUDIO_F32SYS); \
-        SDL_assert(num_channels >= 2); \
-        for (i = cvt->len_cvt / sizeof (float); i; i--, src--, dst -= num_channels) { \
-            dst[0] = dst[1] = *src; \
-            zeroingcode; \
-        } \
-        cvt->len_cvt *= num_channels; \
-        if (cvt->filters[++cvt->filter_index]) { \
-            cvt->filters[cvt->filter_index] (cvt, format); \
-        } \
-    }
-CVT_MONO_TO(Stereo, "stereo", 2, {});
-CVT_MONO_TO(21, "2.1", 3, { dst[2] = 0.0f; });
-CVT_MONO_TO(Quad, "quad", 4, { dst[2] = dst[3] = 0.0f; });
-CVT_MONO_TO(41, "4.1", 5, { dst[2] = dst[3] = dst[4] = 0.0f; });
-CVT_MONO_TO(51, "5.1", 6, { dst[2] = dst[3] = dst[4] = dst[5] = 0.0f; });
-CVT_MONO_TO(61, "6.1", 7, { dst[2] = dst[3] = dst[4] = dst[5] = dst[6] = 0.0f; });
-CVT_MONO_TO(71, "7.1", 8, { dst[2] = dst[3] = dst[4] = dst[5] = dst[6] = dst[7] = 0.0f; });
-#undef CVT_MONO_TO
-
-
-
-/* CONVERT FROM STEREO... */
-/* Stereo duplicates to two front speakers and all other channels are silenced. */
-
 #if HAVE_SSE3_INTRINSICS
 /* Convert from stereo to mono. Average left and right. */
 static void SDLCALL
@@ -358,1119 +317,9 @@ SDL_ConvertStereoToMono_SSE3(SDL_AudioCVT * cvt, SDL_AudioFormat format)
 }
 #endif
 
-/* Convert from stereo to mono. Average left and right. */
-static void SDLCALL
-SDL_ConvertStereoToMono(SDL_AudioCVT * cvt, SDL_AudioFormat format)
-{
-    float *dst = (float *) cvt->buf;
-    const float *src = dst;
-    int i;
-
-    LOG_DEBUG_CONVERT("stereo", "mono");
-    SDL_assert(format == AUDIO_F32SYS);
-
-    for (i = cvt->len_cvt / (sizeof (float) * 2); i; --i, src += 2) {
-        *(dst++) = (src[0] + src[1]) * 0.5f;
-    }
-
-    cvt->len_cvt /= 2;
-    if (cvt->filters[++cvt->filter_index]) {
-        cvt->filters[cvt->filter_index] (cvt, format);
-    }
-}
-
-#define CVT_STEREO_TO(toname, tonamestr, num_channels, zeroingcode) \
-    static void SDLCALL SDL_ConvertStereoTo##toname(SDL_AudioCVT * cvt, SDL_AudioFormat format) { \
-        int i; \
-        const float *src = ((const float *) (cvt->buf + cvt->len_cvt)) - 2; \
-        float *dst = ((float *) (cvt->buf + ((cvt->len_cvt / 2) * num_channels))) - num_channels; \
-        LOG_DEBUG_CONVERT("stereo", tonamestr); \
-        SDL_assert(format == AUDIO_F32SYS); \
-        SDL_assert(num_channels >= 3); \
-        for (i = cvt->len_cvt / (sizeof (float) * 2); i; --i, dst -= num_channels, src -= 2) { \
-            dst[0] = src[0]; \
-            dst[1] = src[1]; \
-            zeroingcode; \
-        } \
-        cvt->len_cvt = (cvt->len_cvt / 2) * num_channels; \
-        if (cvt->filters[++cvt->filter_index]) { \
-            cvt->filters[cvt->filter_index] (cvt, format); \
-        } \
-    }
-
-CVT_STEREO_TO(21, "2.1", 3, { dst[2] = 0.0f; });
-CVT_STEREO_TO(Quad, "quad", 4, { dst[2] = dst[3] = 0.0f; });
-CVT_STEREO_TO(41, "4.1", 5, { dst[2] = dst[3] = dst[4] = 0.0f; });
-CVT_STEREO_TO(51, "5.1", 6, { dst[2] = dst[3] = dst[4] = dst[5] = 0.0f; });
-CVT_STEREO_TO(61, "6.1", 7, { dst[2] = dst[3] = dst[4] = dst[5] = dst[6] = 0.0f; });
-CVT_STEREO_TO(71, "7.1", 8, { dst[2] = dst[3] = dst[4] = dst[5] = dst[6] = dst[7] = 0.0f; });
-#undef CVT_STEREO_TO
-
-
-
-/* CONVERT FROM 2.1... */
-/* 2.1 duplicates to two front speakers (and LFE when available) and all other channels are silenced. */
-
-/* Convert from 2.1 to mono. Average left and right, drop LFE. */
-static void SDLCALL
-SDL_Convert21ToMono(SDL_AudioCVT * cvt, SDL_AudioFormat format)
-{
-    float *dst = (float *) cvt->buf;
-    const float *src = dst;
-    int i;
-
-    LOG_DEBUG_CONVERT("2.1", "mono");
-    SDL_assert(format == AUDIO_F32SYS);
-
-    for (i = cvt->len_cvt / (sizeof (float) * 2); i; --i, src += 3) {
-        *(dst++) = (src[0] + src[1]) * 0.5f;
-    }
-
-    cvt->len_cvt /= 3;
-    if (cvt->filters[++cvt->filter_index]) {
-        cvt->filters[cvt->filter_index] (cvt, format);
-    }
-}
-
-#define CVT_21_TO(toname, tonamestr, num_channels, customcode) \
-    static void SDLCALL SDL_Convert21To##toname(SDL_AudioCVT * cvt, SDL_AudioFormat format) { \
-        int i; \
-        float lf, rf, lfe; \
-        const float *src = (const float *) (cvt->buf + cvt->len_cvt); \
-        float *dst = (float *) (cvt->buf + ((cvt->len_cvt / 3) * num_channels)); \
-        LOG_DEBUG_CONVERT("2.1", tonamestr); \
-        SDL_assert(format == AUDIO_F32SYS); \
-        SDL_assert(num_channels >= 2); \
-        for (i = cvt->len_cvt / (sizeof (float) * 3); i; --i) { \
-            dst -= num_channels; \
-            src -= 2; \
-            lf = src[0]; \
-            rf = src[1]; \
-            lfe = src[2]; \
-            dst[0] = lf; \
-            dst[1] = rf; \
-            customcode; \
-        } \
-        cvt->len_cvt = (cvt->len_cvt / 3) * num_channels; \
-        if (cvt->filters[++cvt->filter_index]) { \
-            cvt->filters[cvt->filter_index] (cvt, format); \
-        } \
-    }
-
-CVT_21_TO(Stereo, "stereo", 2, { (void) lfe; });
-CVT_21_TO(Quad, "quad", 4, { (void) lfe; dst[2] = dst[3] = 0.0f; });
-CVT_21_TO(41, "4.1", 5, { dst[2] = lfe; dst[3] = dst[4] = 0.0f; });
-CVT_21_TO(51, "5.1", 6, { dst[2] = 0.0f; dst[3] = lfe; dst[4] = dst[5] = 0.0f; });
-CVT_21_TO(61, "6.1", 7, { dst[2] = 0.0f; dst[3] = lfe; dst[4] = dst[5] = dst[6] = 0.0f; });
-CVT_21_TO(71, "7.1", 8, { dst[2] = 0.0f; dst[3] = lfe; dst[4] = dst[5] = dst[6] = dst[7] = 0.0f; });
-#undef CVT_21_TO
-
-
-/* CONVERT FROM QUAD... */
-
-static void SDLCALL
-SDL_ConvertQuadToMono(SDL_AudioCVT * cvt, SDL_AudioFormat format)
-{
-    float *dst = (float *) cvt->buf;
-    const float *src = dst;
-    int i;
-
-    LOG_DEBUG_CONVERT("quad", "mono");
-    SDL_assert(format == AUDIO_F32SYS);
-
-    /* !!! FIXME: could benefit from SIMD */
-    for (i = cvt->len_cvt / (sizeof (float) * 4); i; --i, src += 4) {
-        *(dst++) = (src[0] + src[1] + src[3] + src[4]) * 0.25f;
-    }
-
-    cvt->len_cvt /= 4;
-    if (cvt->filters[++cvt->filter_index]) {
-        cvt->filters[cvt->filter_index] (cvt, format);
-    }
-}
-
-static void SDLCALL
-SDL_ConvertQuadToStereo(SDL_AudioCVT * cvt, SDL_AudioFormat format)
-{
-    float *dst = (float *) cvt->buf;
-    const float *src = dst;
-    int i;
-
-    LOG_DEBUG_CONVERT("quad", "stereo");
-    SDL_assert(format == AUDIO_F32SYS);
-
-    /* !!! FIXME: could benefit from SIMD */
-    for (i = cvt->len_cvt / (sizeof (float) * 4); i; --i, src += 4) {
-        const float fl = src[0];
-        const float fr = src[1];
-        const float bl = src[2];
-        const float br = src[3];
-        /* !!! FIXME: FNA/XNA mixes a little of the back right into the left (and back left into the right)...but this can't possibly be right, right...? */
-        *(dst++) = (fl * 0.421000004f) + (bl * 0.358999997f) + (br * 0.219999999f);
-        *(dst++) = (fr * 0.421000004f) + (br * 0.358999997f) + (bl * 0.219999999f);
-    }
-
-    cvt->len_cvt = (cvt->len_cvt / 4) * 2;
-    if (cvt->filters[++cvt->filter_index]) {
-        cvt->filters[cvt->filter_index] (cvt, format);
-    }
-}
-
-static void SDLCALL
-SDL_ConvertQuadTo21(SDL_AudioCVT * cvt, SDL_AudioFormat format)
-{
-    float *dst = (float *) cvt->buf;
-    const float *src = dst;
-    int i;
-
-    LOG_DEBUG_CONVERT("quad", "2.1");
-    SDL_assert(format == AUDIO_F32SYS);
-
-    /* !!! FIXME: could benefit from SIMD */
-    for (i = cvt->len_cvt / (sizeof (float) * 4); i; --i, src += 4) {
-        const float fl = src[0];
-        const float fr = src[1];
-        const float bl = src[2];
-        const float br = src[3];
-        /* !!! FIXME: FNA/XNA mixes a little of the back right into the left (and back left into the right)...but this can't possibly be right, right...? */
-        *(dst++) = (fl * 0.421000004f) + (bl * 0.358999997f) + (br * 0.219999999f);
-        *(dst++) = (fr * 0.421000004f) + (br * 0.358999997f) + (bl * 0.219999999f);
-        *(dst++) = 0.0f;  /* lfe */
-    }
-
-    cvt->len_cvt = (cvt->len_cvt / 4) * 3;
-    if (cvt->filters[++cvt->filter_index]) {
-        cvt->filters[cvt->filter_index] (cvt, format);
-    }
-}
-
-static void SDLCALL
-SDL_ConvertQuadTo41(SDL_AudioCVT * cvt, SDL_AudioFormat format)
-{
-    const float *src = ((const float *) (cvt->buf + cvt->len_cvt)) - 4;
-    float *dst = ((float *) (cvt->buf + ((cvt->len_cvt / 4) * 5))) - 5;
-    int i;
-
-    LOG_DEBUG_CONVERT("quad", "4.1");
-    SDL_assert(format == AUDIO_F32SYS);
-
-    for (i = cvt->len_cvt / (sizeof (float) * 4); i; --i, src -= 4, dst -= 5) {
-        dst[4] = src[3];
-        dst[3] = src[2];
-        dst[2] = 0.0f;  /* LFE */
-        dst[1] = src[1];
-        dst[0] = src[0];
-    }
-
-    cvt->len_cvt = (cvt->len_cvt / 4) * 5;
-    if (cvt->filters[++cvt->filter_index]) {
-        cvt->filters[cvt->filter_index] (cvt, format);
-    }
-}
-
-static void SDLCALL
-SDL_ConvertQuadTo51(SDL_AudioCVT * cvt, SDL_AudioFormat format)
-{
-    const float *src = ((const float *) (cvt->buf + cvt->len_cvt)) - 4;
-    float *dst = ((float *) (cvt->buf + ((cvt->len_cvt / 4) * 6))) - 6;
-    int i;
-
-    LOG_DEBUG_CONVERT("quad", "5.1");
-    SDL_assert(format == AUDIO_F32SYS);
-
-    for (i = cvt->len_cvt / (sizeof (float) * 4); i; --i, src -= 4, dst -= 6) {
-        dst[5] = src[3];
-        dst[4] = src[2];
-        dst[3] = 0.0f;  /* LFE */
-        dst[2] = 0.0f;  /* FC */
-        dst[1] = src[1];
-        dst[0] = src[0];
-    }
-
-    cvt->len_cvt = (cvt->len_cvt / 4) * 6;
-    if (cvt->filters[++cvt->filter_index]) {
-        cvt->filters[cvt->filter_index] (cvt, format);
-    }
-}
-
-static void SDLCALL
-SDL_ConvertQuadTo61(SDL_AudioCVT * cvt, SDL_AudioFormat format)
-{
-    const float *src = ((const float *) (cvt->buf + cvt->len_cvt)) - 4;
-    float *dst = ((float *) (cvt->buf + ((cvt->len_cvt / 4) * 7))) - 7;
-    int i;
-
-    LOG_DEBUG_CONVERT("quad", "6.1");
-    SDL_assert(format == AUDIO_F32SYS);
-
-    /* !!! FIXME: I'm skeptical XNA/FNA's conversion is right, here. */
-
-    for (i = cvt->len_cvt / (sizeof (float) * 4); i; --i, src -= 4, dst -= 7) {
-        const float bl = src[2];
-        const float br = src[3];
-        dst[6] = br * 0.796000004f;
-        dst[5] = bl * 0.796000004f;
-        dst[4] = (bl + br) * 0.5f;  /* average BL+BR to BC */
-        dst[3] = 0.0f;  /* LFE */
-        dst[2] = 0.0f;  /* FC */
-        dst[1] = src[1] * 0.939999998f;
-        dst[0] = src[0] * 0.939999998f;
-    }
-
-    cvt->len_cvt = (cvt->len_cvt / 4) * 7;
-    if (cvt->filters[++cvt->filter_index]) {
-        cvt->filters[cvt->filter_index] (cvt, format);
-    }
-}
-
-static void SDLCALL
-SDL_ConvertQuadTo71(SDL_AudioCVT * cvt, SDL_AudioFormat format)
-{
-    const float *src = ((const float *) (cvt->buf + cvt->len_cvt)) - 4;
-    float *dst = ((float *) (cvt->buf + ((cvt->len_cvt / 4) * 8))) - 8;
-    int i;
-
-    LOG_DEBUG_CONVERT("quad", "7.1");
-    SDL_assert(format == AUDIO_F32SYS);
-
-    for (i = cvt->len_cvt / (sizeof (float) * 4); i; --i, src -= 4, dst -= 8) {
-        dst[7] = 0.0f;  /* SR */
-        dst[6] = 0.0f;  /* SL */
-        dst[5] = src[3];
-        dst[4] = src[2];
-        dst[3] = 0.0f;  /* LFE */
-        dst[2] = 0.0f;  /* FC */
-        dst[1] = src[1];
-        dst[0] = src[0];
-    }
-
-    cvt->len_cvt = (cvt->len_cvt / 4) * 8;
-    if (cvt->filters[++cvt->filter_index]) {
-        cvt->filters[cvt->filter_index] (cvt, format);
-    }
-}
-
-
-/* CONVERT FROM 4.1... */
 
-static void SDLCALL
-SDL_Convert41ToMono(SDL_AudioCVT * cvt, SDL_AudioFormat format)
-{
-    float *dst = (float *) cvt->buf;
-    const float *src = dst;
-    int i;
-
-    LOG_DEBUG_CONVERT("4.1", "mono");
-    SDL_assert(format == AUDIO_F32SYS);
-
-    for (i = cvt->len_cvt / (sizeof (float) * 5); i; --i, src += 5) {
-        *(dst++) = (src[0] + src[1] + src[3] + src[4]) * 0.25f;
-    }
-
-    cvt->len_cvt /= 5;
-    if (cvt->filters[++cvt->filter_index]) {
-        cvt->filters[cvt->filter_index] (cvt, format);
-    }
-}
-
-static void SDLCALL
-SDL_Convert41ToStereo(SDL_AudioCVT * cvt, SDL_AudioFormat format)
-{
-    float *dst = (float *) cvt->buf;
-    const float *src = dst;
-    int i;
-
-    LOG_DEBUG_CONVERT("4.1", "stereo");
-    SDL_assert(format == AUDIO_F32SYS);
-
-    for (i = cvt->len_cvt / (sizeof (float) * 5); i; --i, src += 5) {
-        const float fl = src[0];
-        const float fr = src[1];
-        const float bl = src[3];
-        const float br = src[4];
-        /* !!! FIXME: FNA/XNA mixes a little of the back right into the left (and back left into the right) and a little of the LFE...but this can't possibly be right, right...? */
-        *(dst++) = (fl * 0.374222219f) + (bl * 0.319111109f) + (br * 0.195555553f);
-        *(dst++) = (fr * 0.374222219f) + (br * 0.319111109f) + (bl * 0.195555553f);
-    }
-
-    cvt->len_cvt = (cvt->len_cvt / 5) * 2;
-    if (cvt->filters[++cvt->filter_index]) {
-        cvt->filters[cvt->filter_index] (cvt, format);
-    }
-}
-
-static void SDLCALL
-SDL_Convert41To21(SDL_AudioCVT * cvt, SDL_AudioFormat format)
-{
-    float *dst = (float *) cvt->buf;
-    const float *src = dst;
-    int i;
-
-    LOG_DEBUG_CONVERT("4.1", "2.1");
-    SDL_assert(format == AUDIO_F32SYS);
-
-    for (i = cvt->len_cvt / (sizeof (float) * 5); i; --i, src += 5) {
-        const float fl = src[0];
-        const float fr = src[1];
-        const float lfe = src[2];
-        const float bl = src[3];
-        const float br = src[4];
-        /* !!! FIXME: FNA/XNA mixes a little of the back right into the left (and back left into the right) and a little of the LFE...but this can't possibly be right, right...? */
-        *(dst++) = (fl * 0.374222219f) + (bl * 0.319111109f) + (br * 0.195555553f);
-        *(dst++) = (fr * 0.374222219f) + (br * 0.319111109f) + (bl * 0.195555553f);
-        *(dst++) = lfe;
-    }
-
-    cvt->len_cvt = (cvt->len_cvt / 5) * 3;
-    if (cvt->filters[++cvt->filter_index]) {
-        cvt->filters[cvt->filter_index] (cvt, format);
-    }
-}
-
-static void SDLCALL
-SDL_Convert41ToQuad(SDL_AudioCVT * cvt, SDL_AudioFormat format)
-{
-    float *dst = (float *) cvt->buf;
-    const float *src = dst;
-    int i;
-
-    LOG_DEBUG_CONVERT("4.1", "quad");
-    SDL_assert(format == AUDIO_F32SYS);
-
-    for (i = cvt->len_cvt / (sizeof (float) * 5); i; --i, src += 5) {
-        /* !!! FIXME: FNA/XNA mixes a little of the LFE into every channel...but this can't possibly be right, right...? I just drop the LFE and copy the channels. */
-        *(dst++) = src[0];
-        *(dst++) = src[1];
-        *(dst++) = src[3];
-        *(dst++) = src[4];
-    }
-
-    cvt->len_cvt = (cvt->len_cvt / 5) * 4;
-    if (cvt->filters[++cvt->filter_index]) {
-        cvt->filters[cvt->filter_index] (cvt, format);
-    }
-}
-
-static void SDLCALL
-SDL_Convert41To51(SDL_AudioCVT * cvt, SDL_AudioFormat format)
-{
-    const float *src = ((const float *) (cvt->buf + cvt->len_cvt)) - 5;
-    float *dst = ((float *) (cvt->buf + ((cvt->len_cvt / 5) * 6))) - 6;
-    int i;
-
-    LOG_DEBUG_CONVERT("4.1", "5.1");
-    SDL_assert(format == AUDIO_F32SYS);
-
-    for (i = cvt->len_cvt / (sizeof (float) * 5); i; --i, src -= 5, dst -= 6) {
-        dst[5] = src[4];
-        dst[4] = src[3];
-        dst[3] = src[2];
-        dst[2] = 0.0f;  /* FC */
-        dst[1] = src[1];
-        dst[0] = src[0];
-    }
-
-    cvt->len_cvt = (cvt->len_cvt / 5) * 6;
-    if (cvt->filters[++cvt->filter_index]) {
-        cvt->filters[cvt->filter_index] (cvt, format);
-    }
-}
-
-static void SDLCALL
-SDL_Convert41To61(SDL_AudioCVT * cvt, SDL_AudioFormat format)
-{
-    const float *src = ((const float *) (cvt->buf + cvt->len_cvt)) - 5;
-    float *dst = ((float *) (cvt->buf + ((cvt->len_cvt / 4) * 7))) - 7;
-    int i;
-
-    LOG_DEBUG_CONVERT("4.1", "6.1");
-    SDL_assert(format == AUDIO_F32SYS);
-
-    /* !!! FIXME: I'm skeptical XNA/FNA's conversion is right, here. */
-
-    for (i = cvt->len_cvt / (sizeof (float) * 5); i; --i, src -= 5, dst -= 7) {
-        const float bl = src[3];
-        const float br = src[4];
-        dst[6] = br * 0.796000004f;
-        dst[5] = bl * 0.796000004f;
-        dst[4] = (bl + br) * 0.5f;  /* average BL+BR to BC */
-        dst[3] = src[2];
-        dst[2] = 0.0f;  /* FC */
-        dst[1] = src[1] * 0.939999998f;
-        dst[0] = src[0] * 0.939999998f;
-    }
-
-    cvt->len_cvt = (cvt->len_cvt / 5) * 7;
-    if (cvt->filters[++cvt->filter_index]) {
-        cvt->filters[cvt->filter_index] (cvt, format);
-    }
-}
-
-static void SDLCALL
-SDL_Convert41To71(SDL_AudioCVT * cvt, SDL_AudioFormat format)
-{
-    const float *src = ((const float *) (cvt->buf + cvt->len_cvt)) - 5;
-    float *dst = ((float *) (cvt->buf + ((cvt->len_cvt / 5) * 8))) - 8;
-    int i;
-
-    LOG_DEBUG_CONVERT("4.1", "7.1");
-    SDL_assert(format == AUDIO_F32SYS);
-
-    for (i = cvt->len_cvt / (sizeof (float) * 5); i; --i, src -= 5, dst -= 8) {
-        dst[7] = 0.0f;  /* SR */
-        dst[6] = 0.0f;  /* SL */
-        dst[5] = src[4];
-        dst[4] = src[3];
-        dst[3] = src[2];
-        dst[2] = 0.0f;  /* FC */
-        dst[1] = src[1];
-        dst[0] = src[0];
-    }
-
-    cvt->len_cvt = (cvt->len_cvt / 5) * 8;
-    if (cvt->filters[++cvt->filter_index]) {
-        cvt->filters[cvt->filter_index] (cvt, format);
-    }
-}
-
-
-
-/* CONVERT FROM 5.1... */
-
-static void SDLCALL
-SDL_Convert51ToMono(SDL_AudioCVT * cvt, SDL_AudioFormat format)
-{
-    float *dst = (float *) cvt->buf;
-    const float *src = dst;
-    int i;
-
-    LOG_DEBUG_CONVERT("5.1", "mono");
-    SDL_assert(format == AUDIO_F32SYS);
-
-    for (i = cvt->len_cvt / (sizeof (float) * 6); i; --i, src += 6) {
-        *(dst++) = (src[0] + src[1] + src[2] + src[4] + src[5]) * 0.200000003f;
-    }
-
-    cvt->len_cvt /= 6;
-    if (cvt->filters[++cvt->filter_index]) {
-        cvt->filters[cvt->filter_index] (cvt, format);
-    }
-}
-
-static void SDLCALL
-SDL_Convert51ToStereo(SDL_AudioCVT * cvt, SDL_AudioFormat format)
-{
-    float *dst = (float *) cvt->buf;
-    const float *src = dst;
-    int i;
-
-    LOG_DEBUG_CONVERT("5.1", "stereo");
-    SDL_assert(format == AUDIO_F32SYS);
-
-    for (i = cvt->len_cvt / (sizeof (float) * 6); i; --i, src += 6) {
-        const float fl = src[0];
-        const float fr = src[1];
-        const float fc = src[2];
-        const float bl = src[4];
-        const float br = src[5];
-        const float extra = 0.090909094f / 4.0f;  /* this was the LFE distribution, we'll just split it between the other channels for now. */
-
-        /* !!! FIXME: FNA/XNA mixes a little of the back right into the left (and back left into the right) and a little of the LFE...but this can't possibly be right, right...? */
-        *(dst++) = (fl * (0.294545442f+extra)) + (fc * (0.208181813f+extra)) + (bl * (0.251818180f+extra)) + (br * (0.154545456f+extra));
-        *(dst++) = (fr * (0.294545442f+extra)) + (fc * (0.208181813f+extra)) + (br * (0.251818180f+extra)) + (bl * (0.154545456f+extra));
-    }
-
-    cvt->len_cvt = (cvt->len_cvt / 6) * 2;
-    if (cvt->filters[++cvt->filter_index]) {
-        cvt->filters[cvt->filter_index] (cvt, format);
-    }
-}
-
-static void SDLCALL
-SDL_Convert51To21(SDL_AudioCVT * cvt, SDL_AudioFormat format)
-{
-    float *dst = (float *) cvt->buf;
-    const float *src = dst;
-    int i;
-
-    LOG_DEBUG_CONVERT("5.1", "2.1");
-    SDL_assert(format == AUDIO_F32SYS);
-
-    for (i = cvt->len_cvt / (sizeof (float) * 6); i; --i, src += 6) {
-        const float fl = src[0];
-        const float fr = src[1];
-        const float fc = src[2];
-        const float lfe = src[3];
-        const float bl = src[4];
-        const float br = src[5];
-
-        /* !!! FIXME: FNA/XNA mixes a little of the back right into the left (and back left into the right) and a little of the LFE...but this can't possibly be right, right...? */
-        *(dst++) = (fl * 0.324000001f) + (fc * 0.229000002f) + (bl * 0.277000010f) + (br * 0.170000002f);
-        *(dst++) = (fr * 0.324000001f) + (fc * 0.229000002f) + (br * 0.277000010f) + (bl * 0.170000002f);
-        *(dst++) = lfe;
-    }
-
-    cvt->len_cvt = (cvt->len_cvt / 6) * 3;
-    if (cvt->filters[++cvt->filter_index]) {
-        cvt->filters[cvt->filter_index] (cvt, format);
-    }
-}
-
-static void SDLCALL
-SDL_Convert51ToQuad(SDL_AudioCVT * cvt, SDL_AudioFormat format)
-{
-    float *dst = (float *) cvt->buf;
-    const float *src = dst;
-    int i;
-
-    LOG_DEBUG_CONVERT("5.1", "quad");
-    SDL_assert(format == AUDIO_F32SYS);
-
-    for (i = cvt->len_cvt / (sizeof (float) * 6); i; --i, src += 6) {
-        const float fl = src[0];
-        const float fr = src[1];
-        const float fc = src[2];
-        const float bl = src[4];
-        const float br = src[5];
-        const float extra = 0.047619049f / 2.0f;  /* this was the LFE distribution, we'll just split it between the other channels for now. */
-        *(dst++) = (fl * (0.558095276f+extra)) + (fc * (0.394285709f+extra));
-        *(dst++) = (fr * (0.558095276f+extra)) + (fc * (0.394285709f+extra));
-        *(dst++) = bl;  /* !!! FIXME: XNA/FNA quiets the back speakers here to ~58%, but I'm copying them through. Not sure why they do it like that. */
-        *(dst++) = br;  /* !!! FIXME: XNA/FNA quiets the back speakers here to ~58%, but I'm copying them through. Not sure why they do it like that. */
-    }
-
-    cvt->len_cvt = (cvt->len_cvt / 6) * 4;
-    if (cvt->filters[++cvt->filter_index]) {
-        cvt->filters[cvt->filter_index] (cvt, format);
-    }
-}
-
-static void SDLCALL
-SDL_Convert51To41(SDL_AudioCVT * cvt, SDL_AudioFormat format)
-{
-    float *dst = (float *) cvt->buf;
-    const float *src = dst;
-    int i;
-
-    LOG_DEBUG_CONVERT("5.1", "4.1");
-    SDL_assert(format == AUDIO_F32SYS);
-
-    for (i = cvt->len_cvt / (sizeof (float) * 6); i; --i, src += 6) {
-        const float fl = src[0];
-        const float fr = src[1];
-        const float fc = src[2];
-        const float lfe = src[3];
-        const float bl = src[4];
-        const float br = src[5];
-        *(dst++) = (fl * 0.586000025f) + (fc * 0.414000005f);
-        *(dst++) = (fr * 0.586000025f) + (fc * 0.414000005f);
-        *(dst++) = lfe;
-        *(dst++) = bl;  /* !!! FIXME: XNA/FNA quiets the back speakers here to ~58%, but I'm copying them through. Not sure why they do it like that. */
-        *(dst++) = br;  /* !!! FIXME: XNA/FNA quiets the back speakers here to ~58%, but I'm copying them through. Not sure why they do it like that. */
-    }
-
-    cvt->len_cvt = (cvt->len_cvt / 6) * 5;
-    if (cvt->filters[++cvt->filter_index]) {
-        cvt->filters[cvt->filter_index] (cvt, format);
-    }
-}
-
-static void SDLCALL
-SDL_Convert51To61(SDL_AudioCVT * cvt, SDL_AudioFormat format)
-{
-    const float *src = ((const float *) (cvt->buf + cvt->len_cvt)) - 6;
-    float *dst = ((float *) (cvt->buf + ((cvt->len_cvt / 6) * 7))) - 7;
-    int i;
-
-    LOG_DEBUG_CONVERT("5.1", "6.1");
-    SDL_assert(format == AUDIO_F32SYS);
-
-    /* !!! FIXME: I'm skeptical XNA/FNA's conversion is right, here. Why is it quieting the back speakers instead of copying them through as-is? */
-    for (i = cvt->len_cvt / (sizeof (float) * 6); i; --i, src -= 6, dst -= 7) {
-        const float bl = src[4];
-        const float br = src[5];
-        dst[6] = br * 0.796000004f;
-        dst[5] = bl * 0.796000004f;
-        dst[4] = (bl + br) * 0.5f;  /* average BL+BR to BC */
-        dst[3] = src[3];
-        dst[2] = src[2] * 0.939999998f;
-        dst[1] = src[1] * 0.939999998f;
-        dst[0] = src[0] * 0.939999998f;
-    }
-
-    cvt->len_cvt = (cvt->len_cvt / 6) * 7;
-    if (cvt->filters[++cvt->filter_index]) {
-        cvt->filters[cvt->filter_index] (cvt, format);
-    }
-}
-
-static void SDLCALL
-SDL_Convert51To71(SDL_AudioCVT * cvt, SDL_AudioFormat format)
-{
-    const float *src = ((const float *) (cvt->buf + cvt->len_cvt)) - 6;
-    float *dst = ((float *) (cvt->buf + ((cvt->len_cvt / 6) * 8))) - 8;
-    int i;
-
-    LOG_DEBUG_CONVERT("5.1", "7.1");
-    SDL_assert(format == AUDIO_F32SYS);
-
-    for (i = cvt->len_cvt / (sizeof (float) * 6); i; --i, src -= 6, dst -= 8) {
-        dst[7] = 0.0f;  /* SR */
-        dst[6] = 0.0f;  /* SL */
-        dst[5] = src[5];
-        dst[4] = src[4];
-        dst[3] = src[3];
-        dst[2] = src[2];
-        dst[1] = src[1];
-        dst[0] = src[0];
-    }
-
-    cvt->len_cvt = (cvt->len_cvt / 6) * 8;
-    if (cvt->filters[++cvt->filter_index]) {
-        cvt->filters[cvt->filter_index] (cvt, format);
-    }
-}
-
-
-
-/* CONVERT FROM 6.1... */
-
-static void SDLCALL
-SDL_Convert61ToMono(SDL_AudioCVT * cvt, SDL_AudioFormat format)
-{
-    float *dst = (float *) cvt->buf;
-    const float *src = dst;
-    int i;
-
-    LOG_DEBUG_CONVERT("6.1", "mono");
-    SDL_assert(format == AUDIO_F32SYS);
-
-    for (i = cvt->len_cvt / (sizeof (float) * 7); i; --i, src += 7) {
-        *(dst++) = (src[0] + src[1] + src[2] + src[4] + src[5] + src[6]) * 0.166666672f;
-    }
-
-    cvt->len_cvt /= 7;
-    if (cvt->filters[++cvt->filter_index]) {
-        cvt->filters[cvt->filter_index] (cvt, format);
-    }
-}
-
-static void SDLCALL
-SDL_Convert61ToStereo(SDL_AudioCVT * cvt, SDL_AudioFormat format)
-{
-    float *dst = (float *) cvt->buf;
-    const float *src = dst;
-    int i;
-
-    LOG_DEBUG_CONVERT("6.1", "stereo");
-    SDL_assert(format == AUDIO_F32SYS);
-
-    for (i = cvt->len_cvt / (sizeof (float) * 7); i; --i, src += 7) {
-        const float fl = src[0];
-        const float fr = src[1];
-        const float fc = src[2];
-        const float bc = src[4];
-        const float sl = src[5];
-        const float sr = src[6];
-        const float extra = 0.076923080f / 5.0f;  /* this was the LFE distribution, we'll just split it between the other channels for now. */
-
-        /* !!! FIXME: FNA/XNA mixes a little of the back right into the left (and back left into the right) and a little of the LFE...but this can't possibly be right, right...? */
-        *(dst++) = (fl * (0.247384623f+extra)) + (fc * (0.174461529f+extra)) + (bc * (0.174461529f+extra)) + (sl * (0.226153851f+extra)) + (sr * (0.100615382f+extra));
-        *(dst++) = (fr * (0.247384623f+extra)) + (fc * (0.174461529f+extra)) + (bc * (0.174461529f+extra)) + (sr * (0.226153851f+extra)) + (sl * (0.100615382f+extra));
-    }
-
-    cvt->len_cvt = (cvt->len_cvt / 7) * 2;
-    if (cvt->filters[++cvt->filter_index]) {
-        cvt->filters[cvt->filter_index] (cvt, format);
-    }
-}
-
-static void SDLCALL
-SDL_Convert61To21(SDL_AudioCVT * cvt, SDL_AudioFormat format)
-{
-    float *dst = (float *) cvt->buf;
-    const float *src = dst;
-    int i;
-
-    LOG_DEBUG_CONVERT("6.1", "2.1");
-    SDL_assert(format == AUDIO_F32SYS);
-
-    for (i = cvt->len_cvt / (sizeof (float) * 7); i; --i, src += 7) {
-        const float fl = src[0];
-        const float fr = src[1];
-        const float fc = src[2];
-        const float lfe = src[3];
-        const float bc = src[4];
-        const float sl = src[5];
-        const float sr = src[6];
-
-        /* !!! FIXME: FNA/XNA mixes a little of the back right into the left (and back left into the right) and a little of the LFE...but this can't possibly be right, right...? */
-        *(dst++) = (fl * 0.247384623f) + (fc * 0.174461529f) + (bc * 0.174461529f) + (sl * 0.226153851f) + (sr * 0.100615382f);
-        *(dst++) = (fr * 0.247384623f) + (fc * 0.174461529f) + (bc * 0.174461529f) + (sr * 0.226153851f) + (sl * 0.100615382f);
-        *(dst++) = lfe;
-    }
-
-    cvt->len_cvt = (cvt->len_cvt / 7) * 3;
-    if (cvt->filters[++cvt->filter_index]) {
-        cvt->filters[cvt->filter_index] (cvt, format);
-    }
-}
-
-static void SDLCALL
-SDL_Convert61ToQuad(SDL_AudioCVT * cvt, SDL_AudioFormat format)
-{
-    float *dst = (float *) cvt->buf;
-    const float *src = dst;
-    int i;
-
-    LOG_DEBUG_CONVERT("6.1", "quad");
-    SDL_assert(format == AUDIO_F32SYS);
-
-    for (i = cvt->len_cvt / (sizeof (float) * 7); i; --i, src += 7) {
-        const float fl = src[0];
-        const float fr = src[1];
-        const float fc = src[2];
-        const float bc = src[4];
-        const float sl = src[5];
-        const float sr = src[6];
-        const float extra = 0.040000003f / 3.0f;  /* this was the LFE distribution, we'll just split it between the other channels for now. */
-        const float extra2 = 0.040000003f / 2.0f;  /* this was the LFE distribution, we'll just split it between the other channels for now. */
-        *(dst++) = (fl * (0.463679999f+extra)) + (fc * (0.327360004f+extra)) + (sl * (0.168960005f+extra));
-        *(dst++) = (fr * (0.463679999f+extra)) + (fc * (0.327360004f+extra)) + (sr * (0.168960005f+extra));
-        *(dst++) = (bc * (0.327360004f+extra2)) + (sl * (0.431039989f+extra2));
-        *(dst++) = (bc * (0.327360004f+extra2)) + (sr * (0.431039989f+extra2));
-    }
-
-    cvt->len_cvt = (cvt->len_cvt / 7) * 4;
-    if (cvt->filters[++cvt->filter_index]) {
-        cvt->filters[cvt->filter_index] (cvt, format);
-    }
-}
-
-static void SDLCALL
-SDL_Convert61To41(SDL_AudioCVT * cvt, SDL_AudioFormat format)
-{
-    float *dst = (float *) cvt->buf;
-    const float *src = dst;
-    int i;
-
-    LOG_DEBUG_CONVERT("6.1", "4.1");
-    SDL_assert(format == AUDIO_F32SYS);
-
-    for (i = cvt->len_cvt / (sizeof (float) * 7); i; --i, src += 7) {
-        const float fl = src[0];
-        const float fr = src[1];
-        const float fc = src[2];
-        const float lfe = src[3];
-        const float bc = src[4];
-        const float sl = src[5];
-        const float sr = src[6];
-        *(dst++) = (fl * 0.483000010f) + (fc * 0.340999991f) + (sl * 0.175999999f);
-        *(dst++) = (fr * 0.483000010f) + (fc * 0.340999991f) + (sr * 0.175999999f);
-        *(dst++) = lfe;
-        *(dst++) = (bc * 0.340999991f) + (sl * 0.449000001f);
-        *(dst++) = (bc * 0.340999991f) + (sr * 0.449000001f);
-    }
-
-    cvt->len_cvt = (cvt->len_cvt / 7) * 5;
-    if (cvt->filters[++cvt->filter_index]) {
-        cvt->filters[cvt->filter_index] (cvt, format);
-    }
-}
-
-static void SDLCALL
-SDL_Convert61To51(SDL_AudioCVT * cvt, SDL_AudioFormat format)
-{
-    float *dst = (float *) cvt->buf;
-    const float *src = dst;
-    int i;
-
-    LOG_DEBUG_CONVERT("6.1", "5.1");
-    SDL_assert(format == AUDIO_F32SYS);
-
-    for (i = cvt->len_cvt / (sizeof (float) * 7); i; --i, src += 7) {
-        const float fl = src[0];
-        const float fr = src[1];
-        const float fc = src[2];
-        const float lfe = src[3];
-        const float bc = src[4];
-        const float sl = src[5];
-        const float sr = src[6];
-        /* !!! FIXME: XNA/FNA quiets the front speakers a bunch, but leaves the back speakers at about the same volume. I'm not sure that's right. */
-        *(dst++) = (fl * 0.611000001f) + (sl * 0.223000005f);
-        *(dst++) = (fr * 0.611000001f) + (sr * 0.223000005f);
-        *(dst++) = (fc * 0.611000001f);  /* !!! FIXME: XNA/FNA silence the FC speaker to ~61%, but I'm not sure this is right. */
-        *(dst++) = lfe;
-        *(dst++) = (bc * 0.432000011f) + (sl * 0.568000019f);
-        *(dst++) = (bc * 0.432000011f) + (sr * 0.568000019f);
-    }
-
-    cvt->len_cvt = (cvt->len_cvt / 7) * 6;
-    if (cvt->filters[++cvt->filter_index]) {
-        cvt->filters[cvt->filter_index] (cvt, format);
-    }
-}
-
-static void SDLCALL
-SDL_Convert61To71(SDL_AudioCVT * cvt, SDL_AudioFormat format)
-{
-    const float *src = ((const float *) (cvt->buf + cvt->len_cvt)) - 7;
-    float *dst = ((float *) (cvt->buf + ((cvt->len_cvt / 7) * 8))) - 8;
-    int i;
-
-    LOG_DEBUG_CONVERT("6.1", "7.1");
-    SDL_assert(format == AUDIO_F32SYS);
-
-    for (i = cvt->len_cvt / (sizeof (float) * 7); i; --i, src -= 7, dst -= 8) {
-        const float bc = src[4];
-        dst[7] = src[6];
-        dst[6] = src[5];
-        dst[5] = (bc * 0.707000017f);
-        dst[4] = (bc * 0.707000017f);
-        dst[3] = src[3];
-        dst[2] = src[2];
-        dst[1] = src[1];
-        dst[0] = src[0];
-    }
-
-    cvt->len_cvt = (cvt->len_cvt / 7) * 8;
-    if (cvt->filters[++cvt->filter_index]) {
-        cvt->filters[cvt->filter_index] (cvt, format);
-    }
-}
-
-
-/* CONVERT FROM 7.1... */
-
-static void SDLCALL
-SDL_Convert71ToMono(SDL_AudioCVT * cvt, SDL_AudioFormat format)
-{
-    float *dst = (float *) cvt->buf;
-    const float *src = dst;
-    int i;
-
-    LOG_DEBUG_CONVERT("7.1", "mono");
-    SDL_assert(format == AUDIO_F32SYS);
-
-    /* !!! FIXME: we can probably SIMD this. */
-    for (i = cvt->len_cvt / (sizeof (float) * 8); i; --i, src += 8) {
-        *(dst++) = (src[0] + src[1] + src[2] + src[4] + src[5] + src[6] + src[7]) * 0.143142849f;
-    }
-
-    cvt->len_cvt /= 8;
-    if (cvt->filters[++cvt->filter_index]) {
-        cvt->filters[cvt->filter_index] (cvt, format);
-    }
-}
-
-static void SDLCALL
-SDL_Convert71ToStereo(SDL_AudioCVT * cvt, SDL_AudioFormat format)
-{
-    float *dst = (float *) cvt->buf;
-    const float *src = dst;
-    int i;
-
-    LOG_DEBUG_CONVERT("7.1", "stereo");
-    SDL_assert(format == AUDIO_F32SYS);
-
-    /* !!! FIXME: we can probably SIMD this. */
-    for (i = cvt->len_cvt / (sizeof (float) * 8); i; --i, src += 8) {
-        const float fl = src[0];
-        const float fr = src[1];
-        const float fc = src[2];
-        const float bl = src[4];
-        const float br = src[5];
-        const float sl = src[6];
-        const float sr = src[7];
-        const float extra = 0.066666670f / 6.0f;  /* this was the LFE distribution, we'll just split it between the other channels for now. */
-
-        /* !!! FIXME: FNA/XNA mixes a little of the back right into the left (and back left into the right) and a little of the LFE...but this can't possibly be right, right...? */
-        *(dst++) = (fl * (0.211866662f+extra)) + (fc * (0.150266662f+extra)) + (bl * (0.181066677f+extra)) + (br * (0.111066669f+extra)) + (sl * (0.194133341f+extra)) + (sr * (0.085866667f+extra));
-        *(dst++) = (fr * (0.211866662f+extra)) + (fc * (0.150266662f+extra)) + (br * (0.181066677f+extra)) + (bl * (0.111066669f+extra)) + (sr * (0.194133341f+extra)) + (sl * (0.085866667f+extra));
-    }
-
-    cvt->len_cvt = (cvt->len_cvt / 8) * 2;
-    if (cvt->filters[++cvt->filter_index]) {
-        cvt->filters[cvt->filter_index] (cvt, format);
-    }
-}
-
-static void SDLCALL
-SDL_Convert71To21(SDL_AudioCVT * cvt, SDL_AudioFormat format)
-{
-    float *dst = (float *) cvt->buf;
-    const float *src = dst;
-    int i;
-
-    LOG_DEBUG_CONVERT("7.1", "2.1");
-    SDL_assert(format == AUDIO_F32SYS);
-
-    /* !!! FIXME: we can probably SIMD this. */
-    for (i = cvt->len_cvt / (sizeof (float) * 8); i; --i, src += 8) {
-        const float fl = src[0];
-        const float fr = src[1];
-        const float fc = src[2];
-        const float lfe = src[3];
-        const float bl = src[4];
-        const float br = src[5];
-        const float sl = src[6];
-        const float sr = src[7];
-
-        /* !!! FIXME: FNA/XNA mixes a little of the back right into the left (and back left into the right) and a little of the LFE...but this can't possibly be right, right...? */
-        *(dst++) = (fl * 0.211866662f) + (fc * 0.150266662f) + (bl * 0.181066677f) + (br * 0.111066669f) + (sl * 0.194133341f) + (sr * 0.085866667f);
-        *(dst++) = (fr * 0.211866662f) + (fc * 0.150266662f) + (br * 0.181066677f) + (bl * 0.111066669f) + (sr * 0.194133341f) + (sl * 0.085866667f);
-        *(dst++) = lfe;
-    }
-
-    cvt->len_cvt = (cvt->len_cvt / 8) * 3;
-    if (cvt->filters[++cvt->filter_index]) {
-        cvt->filters[cvt->filter_index] (cvt, format);
-    }
-}
-
-static void SDLCALL
-SDL_Convert71ToQuad(SDL_AudioCVT * cvt, SDL_AudioFormat format)
-{
-    float *dst = (float *) cvt->buf;
-    const float *src = dst;
-    int i;
-
-    LOG_DEBUG_CONVERT("7.1", "quad");
-    SDL_assert(format == AUDIO_F32SYS);
-
-    for (i = cvt->len_cvt / (sizeof (float) * 8); i; --i, src += 8) {
-        const float fl = src[0];
-        const float fr = src[1];
-        const float fc = src[2];
-        const float bl = src[4];
-        const float br = src[5];
-        const float sl = src[6];
-        const float sr = src[7];
-        const float extra = 0.034482758f / 3.0f;  /* this was the LFE distribution, we'll just split it between the other channels for now. */
-        const float extra2 = 0.034482758f / 2.0f;  /* this was the LFE distribution, we'll just split it between the other channels for now. */
-        *(dst++) = (fl * (0.466344833f+extra)) + (fc * (0.329241365f+extra)) + (sl * (0.169931039f+extra));
-        *(dst++) = (fr * (0.466344833f+extra)) + (fc * (0.329241365f+extra)) + (sr * (0.169931039f+extra));
-        *(dst++) = (bl * (0.466344833f+extra2)) + (sl * (0.433517247f+extra2));
-        *(dst++) = (br * (0.466344833f+extra2)) + (sr * (0.433517247f+extra2));
-    }
-
-    cvt->len_cvt = (cvt->len_cvt / 8) * 4;
-    if (cvt->filters[++cvt->filter_index]) {
-        cvt->filters[cvt->filter_index] (cvt, format);
-    }
-}
-
-static void SDLCALL
-SDL_Convert71To41(SDL_AudioCVT * cvt, SDL_AudioFormat format)
-{
-    float *dst = (float *) cvt->buf;
-    const float *src = dst;
-    int i;
-
-    LOG_DEBUG_CONVERT("7.1", "4.1");
-    SDL_assert(format == AUDIO_F32SYS);
-
-    for (i = cvt->len_cvt / (sizeof (float) * 8); i; --i, src += 8) {
-        const float fl = src[0];
-        const float fr = src[1];
-        const float fc = src[2];
-        const float lfe = src[3];
-        const float bl = src[4];
-        const float br = src[5];
-        const float sl = src[6];
-        const float sr = src[7];
-        *(dst++) = (fl * 0.483000010f) + (fc * 0.340999991f) + (sl * 0.175999999f);
-        *(dst++) = (fr * 0.483000010f) + (fc * 0.340999991f) + (sr * 0.175999999f);
-        *(dst++) = lfe;
-        *(dst++) = (bl * 0.483000010f) + (sl * 0.449000001f);
-        *(dst++) = (br * 0.483000010f) + (sr * 0.449000001f);
-    }
-
-    cvt->len_cvt = (cvt->len_cvt / 8) * 5;
-    if (cvt->filters[++cvt->filter_index]) {
-        cvt->filters[cvt->filter_index] (cvt, format);
-    }
-}
-
-static void SDLCALL
-SDL_Convert71To51(SDL_AudioCVT * cvt, SDL_AudioFormat format)
-{
-    float *dst = (float *) cvt->buf;
-    const float *src = dst;
-    int i;
-
-    LOG_DEBUG_CONVERT("7.1", "5.1");
-    SDL_assert(format == AUDIO_F32SYS);
-
-    for (i = cvt->len_cvt / (sizeof (float) * 8); i; --i, src += 8) {
-        const float fl = src[0];
-        const float fr = src[1];
-        const float fc = src[2];
-        const float lfe = src[3];
-        const float bl = src[4];
-        const float br = src[5];
-        const float sl = src[6];
-        const float sr = src[7];
-        /* !!! FIXME: XNA/FNA quiets the front speakers a bunch, but leaves the back speakers at about the same volume. I'm not sure that's right. */
-        *(dst++) = (fl * 0.518000007f) + (sl * 0.188999996f);
-        *(dst++) = (fr * 0.518000007f) + (sr * 0.188999996f);
-        *(dst++) = (fc * 0.518000007f);  /* !!! FIXME: XNA/FNA silence the FC speaker to ~51%, but I'm not sure this is right. */
-        *(dst++) = lfe;
-        *(dst++) = (bl * 0.518000007f) + (sl * 0.188999996f);
-        *(dst++) = (br * 0.518000007f) + (sr * 0.188999996f);
-    }
-
-    cvt->len_cvt = (cvt->len_cvt / 8) * 6;
-    if (cvt->filters[++cvt->filter_index]) {
-        cvt->filters[cvt->filter_index] (cvt, format);
-    }
-}
-
-static void SDLCALL
-SDL_Convert71To61(SDL_AudioCVT * cvt, SDL_AudioFormat format)
-{
-    float *dst = (float *) cvt->buf;
-    const float *src = dst;
-    int i;
-
-    LOG_DEBUG_CONVERT("7.1", "6.1");
-    SDL_assert(format == AUDIO_F32SYS);
-
-    for (i = cvt->len_cvt / (sizeof (float) * 8); i; --i, src += 8) {
-        const float fl = src[0];
-        const float fr = src[1];
-        const float fc = src[2];
-        const float lfe = src[3];
-        const float bl = src[4];
-        const float br = src[5];
-        const float sl = src[6];
-        const float sr = src[7];
-        /* !!! FIXME: XNA/FNA quiets the front speakers a bunch, but leaves the back speakers at about the same volume. I'm not sure that's right. */
-        *(dst++) = (fl * 0.541000009f);
-        *(dst++) = (fr * 0.541000009f);
-        *(dst++) = (fc * 0.541000009f);  /* !!! FIXME: XNA/FNA silence the FC speaker to ~61%, but I'm not sure this is right. */
-        *(dst++) = lfe;
-        *(dst++) = (bl * 0.287999988f) + (br * 0.287999988f);
-        *(dst++) = (bl * 0.458999991f) + (sl * 0.541000009f);
-        *(dst++) = (br * 0.458999991f) + (sr * 0.541000009f);
-    }
-
-    cvt->len_cvt = (cvt->len_cvt / 8) * 6;
-    if (cvt->filters[++cvt->filter_index]) {
-        cvt->filters[cvt->filter_index] (cvt, format);
-    }
-}
-
-static const SDL_AudioFilter channel_converters[8][8] = {   /* from][to] */
-    { NULL, SDL_ConvertMonoToStereo, SDL_ConvertMonoTo21, SDL_ConvertMonoToQuad, SDL_ConvertMonoTo41, SDL_ConvertMonoTo51, SDL_ConvertMonoTo61, SDL_ConvertMonoTo71 },
-    { SDL_ConvertStereoToMono, NULL, SDL_ConvertStereoTo21, SDL_ConvertStereoToQuad, SDL_ConvertStereoTo41, SDL_ConvertStereoTo51, SDL_ConvertStereoTo61, SDL_ConvertStereoTo71 },
-    { SDL_Convert21ToMono, SDL_Convert21ToStereo, NULL, SDL_Convert21ToQuad, SDL_Convert21To41, SDL_Convert21To51, SDL_Convert21To61, SDL_Convert21To71 },
-    { SDL_ConvertQuadToMono, SDL_ConvertQuadToStereo, SDL_ConvertQuadTo21, NULL, SDL_ConvertQuadTo41, SDL_ConvertQuadTo51, SDL_ConvertQuadTo61, SDL_ConvertQuadTo71 },
-    { SDL_Convert41ToMono, SDL_Convert41ToStereo, SDL_Convert41To21, SDL_Convert41ToQuad, NULL, SDL_Convert41To51, SDL_Convert41To61, SDL_Convert41To71 },
-    { SDL_Convert51ToMono, SDL_Convert51ToStereo, SDL_Convert51To21, SDL_Convert51ToQuad, SDL_Convert51To41, NULL, SDL_Convert51To61, SDL_Convert51To71 },
-    { SDL_Convert61ToMono, SDL_Convert61ToStereo, SDL_Convert61To21, SDL_Convert61ToQuad, SDL_Convert61To41, SDL_Convert61To51, NULL, SDL_Convert61To71 },
-    { SDL_Convert71ToMono, SDL_Convert71ToStereo, SDL_Convert71To21, SDL_Convert71ToQuad, SDL_Convert71To41, SDL_Convert71To51, SDL_Convert71To61, NULL }
-};
+/* Include the autogenerated channel converters... */
+#include "SDL_audio_channel_converters.h"