Commit 7b79e710 authored by David Reid's avatar David Reid

Set up some very basic and experimental infrastructure for channel mapping.

parent a16d3e64
...@@ -450,8 +450,9 @@ struct mal_dsp ...@@ -450,8 +450,9 @@ struct mal_dsp
mal_dsp_read_proc onRead; mal_dsp_read_proc onRead;
void* pUserDataForOnRead; void* pUserDataForOnRead;
mal_src src; // For sample rate conversion. mal_src src; // For sample rate conversion.
mal_uint8 channelMapInPostMix[MAL_MAX_CHANNELS]; // <-- When mixing, new channels may need to be created. This represents the channel map after mixing.
mal_uint8 channelShuffleTable[MAL_MAX_CHANNELS]; mal_uint8 channelShuffleTable[MAL_MAX_CHANNELS];
mal_bool32 isUsingForeignChannelMap : 1; mal_bool32 isChannelMappingRequired : 1;
mal_bool32 isSRCRequired : 1; mal_bool32 isSRCRequired : 1;
mal_bool32 isPassthrough : 1; // <-- Will be set to true when the DSP pipeline is an optimized passthrough. mal_bool32 isPassthrough : 1; // <-- Will be set to true when the DSP pipeline is an optimized passthrough.
}; };
...@@ -3677,8 +3678,8 @@ static mal_result mal_device_init__alsa(mal_context* pContext, mal_device_type t ...@@ -3677,8 +3678,8 @@ static mal_result mal_device_init__alsa(mal_context* pContext, mal_device_type t
if (pDeviceID == NULL) { if (pDeviceID == NULL) {
mal_strncpy_s(deviceName, sizeof(deviceName), "default", (size_t)-1); mal_strncpy_s(deviceName, sizeof(deviceName), "default", (size_t)-1);
} else { } else {
// For now, convert "hw" devices to "plughw". The reason for this is that mini_al is still a // For now, convert "hw" devices to "plughw". The reason for this is that mini_al has not been thoroughly tested
// a quite unstable with non "plughw" devices. // with non "plughw" devices.
if (pDeviceID->str[0] == 'h' && pDeviceID->str[1] == 'w' && pDeviceID->str[2] == ':') { if (pDeviceID->str[0] == 'h' && pDeviceID->str[1] == 'w' && pDeviceID->str[2] == ':') {
deviceName[0] = 'p'; deviceName[1] = 'l'; deviceName[2] = 'u'; deviceName[3] = 'g'; deviceName[0] = 'p'; deviceName[1] = 'l'; deviceName[2] = 'u'; deviceName[3] = 'g';
mal_strncpy_s(deviceName+4, sizeof(deviceName-4), pDeviceID->str, (size_t)-1); mal_strncpy_s(deviceName+4, sizeof(deviceName-4), pDeviceID->str, (size_t)-1);
...@@ -6126,8 +6127,7 @@ void mal_pcm_convert(void* pOut, mal_format formatOut, const void* pIn, mal_form ...@@ -6126,8 +6127,7 @@ void mal_pcm_convert(void* pOut, mal_format formatOut, const void* pIn, mal_form
} }
} }
#if 0 static void mal_rearrange_channels(float* pFrame, mal_uint32 channels, mal_uint8 channelMap[18])
static void mal_rearrange_channels(float* pFrame, mal_uint32 channels, mal_uint32 channelMap[18])
{ {
float temp; float temp;
switch (channels) { switch (channels) {
...@@ -6151,7 +6151,6 @@ static void mal_rearrange_channels(float* pFrame, mal_uint32 channels, mal_uint3 ...@@ -6151,7 +6151,6 @@ static void mal_rearrange_channels(float* pFrame, mal_uint32 channels, mal_uint3
case 1: temp = pFrame[ 0]; pFrame[ 0] = pFrame[channelMap[ 0]]; pFrame[channelMap[ 0]] = temp; case 1: temp = pFrame[ 0]; pFrame[ 0] = pFrame[channelMap[ 0]]; pFrame[channelMap[ 0]] = temp;
} }
} }
#endif
static void mal_dsp_mix_channels__dec(float* pFramesOut, mal_uint32 channelsOut, const float* pFramesIn, mal_uint32 channelsIn, mal_uint32 frameCount, mal_channel_mix_mode mode) static void mal_dsp_mix_channels__dec(float* pFramesOut, mal_uint32 channelsOut, const float* pFramesIn, mal_uint32 channelsIn, mal_uint32 frameCount, mal_channel_mix_mode mode)
{ {
...@@ -6333,6 +6332,7 @@ mal_uint32 mal_dsp__src_on_read(mal_uint32 frameCount, void* pFramesOut, void* p ...@@ -6333,6 +6332,7 @@ mal_uint32 mal_dsp__src_on_read(mal_uint32 frameCount, void* pFramesOut, void* p
mal_result mal_dsp_init(mal_dsp_config* pConfig, mal_dsp_read_proc onRead, void* pUserData, mal_dsp* pDSP) mal_result mal_dsp_init(mal_dsp_config* pConfig, mal_dsp_read_proc onRead, void* pUserData, mal_dsp* pDSP)
{ {
if (pDSP == NULL) return MAL_INVALID_ARGS; if (pDSP == NULL) return MAL_INVALID_ARGS;
mal_zero_object(pDSP);
pDSP->config = *pConfig; pDSP->config = *pConfig;
pDSP->onRead = onRead; pDSP->onRead = onRead;
pDSP->pUserDataForOnRead = pUserData; pDSP->pUserDataForOnRead = pUserData;
...@@ -6358,15 +6358,62 @@ mal_result mal_dsp_init(mal_dsp_config* pConfig, mal_dsp_read_proc onRead, void* ...@@ -6358,15 +6358,62 @@ mal_result mal_dsp_init(mal_dsp_config* pConfig, mal_dsp_read_proc onRead, void*
} }
} }
pDSP->isUsingForeignChannelMap = MAL_FALSE;
for (mal_uint32 i = 0; i < MAL_MAX_CHANNELS; ++i) {
if (pConfig->channelMapIn[i] != pConfig->channelMapOut[i]) { pDSP->isChannelMappingRequired = MAL_FALSE;
pDSP->isUsingForeignChannelMap = MAL_TRUE; if (pConfig->channelMapIn[0] != MAL_CHANNEL_NONE && pConfig->channelMapOut[0] != MAL_CHANNEL_NONE) { // <-- Channel mapping will be ignored if the first channel map is MAL_CHANNEL_NONE.
break; // When using channel mapping we need to figure out a shuffling table. The first thing to do is convert the input channel map
// so that it contains the same number of channels as the output channel count.
mal_uint32 channelsMin = mal_min(pConfig->channelsIn, pConfig->channelsOut);
for (mal_uint32 iChannel = 0; iChannel < channelsMin; ++iChannel) {
pDSP->channelMapInPostMix[iChannel] = pConfig->channelMapIn[iChannel];
}
// Any excess channels need to be filled with the relevant channels from the output channel map. Currently we're justing filling it with
// the first channels that are not present in the input channel map.
if (pConfig->channelsOut > pConfig->channelsIn) {
for (mal_uint32 iChannel = pConfig->channelsIn; iChannel < pConfig->channelsOut; ++iChannel) {
mal_uint8 newChannel = MAL_CHANNEL_NONE;
for (mal_uint32 iChannelOut = 0; iChannelOut < pConfig->channelsOut; ++iChannelOut) {
mal_bool32 exists = MAL_FALSE;
for (mal_uint32 iChannelIn = 0; iChannelIn < pConfig->channelsIn; ++iChannelIn) {
if (pConfig->channelMapOut[iChannelOut] == pConfig->channelMapIn[iChannelIn]) {
exists = MAL_TRUE;
break;
}
}
if (!exists) {
newChannel = pConfig->channelMapOut[iChannelOut];
break;
}
}
pDSP->channelMapInPostMix[iChannel] = newChannel;
}
}
// We only need to do a channel mapping if the map after mixing is different to the final output map.
for (mal_uint32 iChannel = 0; iChannel < pConfig->channelsOut; ++iChannel) {
if (pDSP->channelMapInPostMix[iChannel] != pConfig->channelMapOut[iChannel]) {
pDSP->isChannelMappingRequired = MAL_TRUE;
break;
}
}
// Now we need to create the shuffling table.
if (pDSP->isChannelMappingRequired) {
for (mal_uint32 iChannelIn = 0; iChannelIn < pConfig->channelsOut; ++iChannelIn) {
for (mal_uint32 iChannelOut = 0; iChannelOut < pConfig->channelsOut; ++iChannelOut) {
if (pDSP->channelMapInPostMix[iChannelOut] == pConfig->channelMapOut[iChannelIn]) {
pDSP->channelShuffleTable[iChannelOut] = (mal_uint8)iChannelOut;
}
}
}
} }
} }
if (pConfig->formatIn == pConfig->formatOut && pConfig->channelsIn == pConfig->channelsOut && pConfig->sampleRateIn == pConfig->sampleRateOut && !pDSP->isUsingForeignChannelMap) { if (pConfig->formatIn == pConfig->formatOut && pConfig->channelsIn == pConfig->channelsOut && pConfig->sampleRateIn == pConfig->sampleRateOut && !pDSP->isChannelMappingRequired) {
pDSP->isPassthrough = MAL_TRUE; pDSP->isPassthrough = MAL_TRUE;
} else { } else {
pDSP->isPassthrough = MAL_FALSE; pDSP->isPassthrough = MAL_FALSE;
...@@ -6427,6 +6474,11 @@ mal_uint32 mal_dsp_read_frames(mal_dsp* pDSP, mal_uint32 frameCount, void* pFram ...@@ -6427,6 +6474,11 @@ mal_uint32 mal_dsp_read_frames(mal_dsp* pDSP, mal_uint32 frameCount, void* pFram
// TODO: Channel mapping. // TODO: Channel mapping.
if (pDSP->isChannelMappingRequired) {
for (mal_uint32 i = 0; i < framesRead; ++i) {
mal_rearrange_channels(pFrames[iFrames] + (i * pDSP->config.channelsOut), pDSP->config.channelsOut, pDSP->channelShuffleTable);
}
}
// Final conversion to output format. // Final conversion to output format.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment