/* Based off the speaker configurations mentioned here: https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/content/ksmedia/ns-ksmedia-ksaudio_channel_config */
switch (channels)
{
case 1:
{
channelMap[0] = MA_CHANNEL_MONO;
pChannelMap[0] = MA_CHANNEL_MONO;
} break;
case 2:
{
channelMap[0] = MA_CHANNEL_FRONT_LEFT;
channelMap[1] = MA_CHANNEL_FRONT_RIGHT;
pChannelMap[0] = MA_CHANNEL_FRONT_LEFT;
pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT;
} break;
case 3: /* Not defined, but best guess. */
{
channelMap[0] = MA_CHANNEL_FRONT_LEFT;
channelMap[1] = MA_CHANNEL_FRONT_RIGHT;
channelMap[2] = MA_CHANNEL_FRONT_CENTER;
pChannelMap[0] = MA_CHANNEL_FRONT_LEFT;
pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT;
pChannelMap[2] = MA_CHANNEL_FRONT_CENTER;
} break;
case 4:
{
#ifndef MA_USE_QUAD_MICROSOFT_CHANNEL_MAP
/* Surround. Using the Surround profile has the advantage of the 3rd channel (MA_CHANNEL_FRONT_CENTER) mapping nicely with higher channel counts. */
channelMap[0] = MA_CHANNEL_FRONT_LEFT;
channelMap[1] = MA_CHANNEL_FRONT_RIGHT;
channelMap[2] = MA_CHANNEL_FRONT_CENTER;
channelMap[3] = MA_CHANNEL_BACK_CENTER;
pChannelMap[0] = MA_CHANNEL_FRONT_LEFT;
pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT;
pChannelMap[2] = MA_CHANNEL_FRONT_CENTER;
pChannelMap[3] = MA_CHANNEL_BACK_CENTER;
#else
/* Quad. */
channelMap[0] = MA_CHANNEL_FRONT_LEFT;
channelMap[1] = MA_CHANNEL_FRONT_RIGHT;
channelMap[2] = MA_CHANNEL_BACK_LEFT;
channelMap[3] = MA_CHANNEL_BACK_RIGHT;
pChannelMap[0] = MA_CHANNEL_FRONT_LEFT;
pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT;
pChannelMap[2] = MA_CHANNEL_BACK_LEFT;
pChannelMap[3] = MA_CHANNEL_BACK_RIGHT;
#endif
} break;
case 5: /* Not defined, but best guess. */
{
channelMap[0] = MA_CHANNEL_FRONT_LEFT;
channelMap[1] = MA_CHANNEL_FRONT_RIGHT;
channelMap[2] = MA_CHANNEL_FRONT_CENTER;
channelMap[3] = MA_CHANNEL_BACK_LEFT;
channelMap[4] = MA_CHANNEL_BACK_RIGHT;
pChannelMap[0] = MA_CHANNEL_FRONT_LEFT;
pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT;
pChannelMap[2] = MA_CHANNEL_FRONT_CENTER;
pChannelMap[3] = MA_CHANNEL_BACK_LEFT;
pChannelMap[4] = MA_CHANNEL_BACK_RIGHT;
} break;
case 6:
{
channelMap[0] = MA_CHANNEL_FRONT_LEFT;
channelMap[1] = MA_CHANNEL_FRONT_RIGHT;
channelMap[2] = MA_CHANNEL_FRONT_CENTER;
channelMap[3] = MA_CHANNEL_LFE;
channelMap[4] = MA_CHANNEL_SIDE_LEFT;
channelMap[5] = MA_CHANNEL_SIDE_RIGHT;
pChannelMap[0] = MA_CHANNEL_FRONT_LEFT;
pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT;
pChannelMap[2] = MA_CHANNEL_FRONT_CENTER;
pChannelMap[3] = MA_CHANNEL_LFE;
pChannelMap[4] = MA_CHANNEL_SIDE_LEFT;
pChannelMap[5] = MA_CHANNEL_SIDE_RIGHT;
} break;
case 7: /* Not defined, but best guess. */
{
channelMap[0] = MA_CHANNEL_FRONT_LEFT;
channelMap[1] = MA_CHANNEL_FRONT_RIGHT;
channelMap[2] = MA_CHANNEL_FRONT_CENTER;
channelMap[3] = MA_CHANNEL_LFE;
channelMap[4] = MA_CHANNEL_BACK_CENTER;
channelMap[5] = MA_CHANNEL_SIDE_LEFT;
channelMap[6] = MA_CHANNEL_SIDE_RIGHT;
pChannelMap[0] = MA_CHANNEL_FRONT_LEFT;
pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT;
pChannelMap[2] = MA_CHANNEL_FRONT_CENTER;
pChannelMap[3] = MA_CHANNEL_LFE;
pChannelMap[4] = MA_CHANNEL_BACK_CENTER;
pChannelMap[5] = MA_CHANNEL_SIDE_LEFT;
pChannelMap[6] = MA_CHANNEL_SIDE_RIGHT;
} break;
case 8:
default:
{
channelMap[0] = MA_CHANNEL_FRONT_LEFT;
channelMap[1] = MA_CHANNEL_FRONT_RIGHT;
channelMap[2] = MA_CHANNEL_FRONT_CENTER;
channelMap[3] = MA_CHANNEL_LFE;
channelMap[4] = MA_CHANNEL_BACK_LEFT;
channelMap[5] = MA_CHANNEL_BACK_RIGHT;
channelMap[6] = MA_CHANNEL_SIDE_LEFT;
channelMap[7] = MA_CHANNEL_SIDE_RIGHT;
pChannelMap[0] = MA_CHANNEL_FRONT_LEFT;
pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT;
pChannelMap[2] = MA_CHANNEL_FRONT_CENTER;
pChannelMap[3] = MA_CHANNEL_LFE;
pChannelMap[4] = MA_CHANNEL_BACK_LEFT;
pChannelMap[5] = MA_CHANNEL_BACK_RIGHT;
pChannelMap[6] = MA_CHANNEL_SIDE_LEFT;
pChannelMap[7] = MA_CHANNEL_SIDE_RIGHT;
} break;
}
/* Remainder. */
if (channels > 8) {
ma_uint32 iChannel;
for (iChannel = 8; iChannel < MA_MAX_CHANNELS; ++iChannel) {
/* In Vorbis' type 0 channel mapping, the first two channels are not always the standard left/right - it will have the center speaker where the right usually goes. Why?! */
switch (channels)
{
case 1:
{
channelMap[0] = MA_CHANNEL_MONO;
pChannelMap[0] = MA_CHANNEL_MONO;
} break;
case 2:
{
channelMap[0] = MA_CHANNEL_LEFT;
channelMap[1] = MA_CHANNEL_RIGHT;
pChannelMap[0] = MA_CHANNEL_LEFT;
pChannelMap[1] = MA_CHANNEL_RIGHT;
} break;
case 3:
{
channelMap[0] = MA_CHANNEL_FRONT_LEFT;
channelMap[1] = MA_CHANNEL_FRONT_CENTER;
channelMap[2] = MA_CHANNEL_FRONT_RIGHT;
pChannelMap[0] = MA_CHANNEL_FRONT_LEFT;
pChannelMap[1] = MA_CHANNEL_FRONT_CENTER;
pChannelMap[2] = MA_CHANNEL_FRONT_RIGHT;
} break;
case 4:
{
channelMap[0] = MA_CHANNEL_FRONT_LEFT;
channelMap[1] = MA_CHANNEL_FRONT_RIGHT;
channelMap[2] = MA_CHANNEL_BACK_LEFT;
channelMap[3] = MA_CHANNEL_BACK_RIGHT;
pChannelMap[0] = MA_CHANNEL_FRONT_LEFT;
pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT;
pChannelMap[2] = MA_CHANNEL_BACK_LEFT;
pChannelMap[3] = MA_CHANNEL_BACK_RIGHT;
} break;
case 5:
{
channelMap[0] = MA_CHANNEL_FRONT_LEFT;
channelMap[1] = MA_CHANNEL_FRONT_CENTER;
channelMap[2] = MA_CHANNEL_FRONT_RIGHT;
channelMap[3] = MA_CHANNEL_BACK_LEFT;
channelMap[4] = MA_CHANNEL_BACK_RIGHT;
pChannelMap[0] = MA_CHANNEL_FRONT_LEFT;
pChannelMap[1] = MA_CHANNEL_FRONT_CENTER;
pChannelMap[2] = MA_CHANNEL_FRONT_RIGHT;
pChannelMap[3] = MA_CHANNEL_BACK_LEFT;
pChannelMap[4] = MA_CHANNEL_BACK_RIGHT;
} break;
case 6:
{
channelMap[0] = MA_CHANNEL_FRONT_LEFT;
channelMap[1] = MA_CHANNEL_FRONT_CENTER;
channelMap[2] = MA_CHANNEL_FRONT_RIGHT;
channelMap[3] = MA_CHANNEL_BACK_LEFT;
channelMap[4] = MA_CHANNEL_BACK_RIGHT;
channelMap[5] = MA_CHANNEL_LFE;
pChannelMap[0] = MA_CHANNEL_FRONT_LEFT;
pChannelMap[1] = MA_CHANNEL_FRONT_CENTER;
pChannelMap[2] = MA_CHANNEL_FRONT_RIGHT;
pChannelMap[3] = MA_CHANNEL_BACK_LEFT;
pChannelMap[4] = MA_CHANNEL_BACK_RIGHT;
pChannelMap[5] = MA_CHANNEL_LFE;
} break;
case 7:
{
channelMap[0] = MA_CHANNEL_FRONT_LEFT;
channelMap[1] = MA_CHANNEL_FRONT_CENTER;
channelMap[2] = MA_CHANNEL_FRONT_RIGHT;
channelMap[3] = MA_CHANNEL_SIDE_LEFT;
channelMap[4] = MA_CHANNEL_SIDE_RIGHT;
channelMap[5] = MA_CHANNEL_BACK_CENTER;
channelMap[6] = MA_CHANNEL_LFE;
pChannelMap[0] = MA_CHANNEL_FRONT_LEFT;
pChannelMap[1] = MA_CHANNEL_FRONT_CENTER;
pChannelMap[2] = MA_CHANNEL_FRONT_RIGHT;
pChannelMap[3] = MA_CHANNEL_SIDE_LEFT;
pChannelMap[4] = MA_CHANNEL_SIDE_RIGHT;
pChannelMap[5] = MA_CHANNEL_BACK_CENTER;
pChannelMap[6] = MA_CHANNEL_LFE;
} break;
case 8:
default:
{
channelMap[0] = MA_CHANNEL_FRONT_LEFT;
channelMap[1] = MA_CHANNEL_FRONT_CENTER;
channelMap[2] = MA_CHANNEL_FRONT_RIGHT;
channelMap[3] = MA_CHANNEL_SIDE_LEFT;
channelMap[4] = MA_CHANNEL_SIDE_RIGHT;
channelMap[5] = MA_CHANNEL_BACK_LEFT;
channelMap[6] = MA_CHANNEL_BACK_RIGHT;
channelMap[7] = MA_CHANNEL_LFE;
pChannelMap[0] = MA_CHANNEL_FRONT_LEFT;
pChannelMap[1] = MA_CHANNEL_FRONT_CENTER;
pChannelMap[2] = MA_CHANNEL_FRONT_RIGHT;
pChannelMap[3] = MA_CHANNEL_SIDE_LEFT;
pChannelMap[4] = MA_CHANNEL_SIDE_RIGHT;
pChannelMap[5] = MA_CHANNEL_BACK_LEFT;
pChannelMap[6] = MA_CHANNEL_BACK_RIGHT;
pChannelMap[7] = MA_CHANNEL_LFE;
} break;
}
/* Remainder. */
if (channels > 8) {
ma_uint32 iChannel;
for (iChannel = 8; iChannel < MA_MAX_CHANNELS; ++iChannel) {