mirror of
https://github.com/mackron/miniaudio.git
synced 2026-04-22 00:06:59 +02:00
Set up some very basic and experimental infrastructure for channel mapping.
This commit is contained in:
@@ -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
|
|||||||
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
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#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
|
|||||||
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
|
|||||||
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*
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
|||||||
|
|
||||||
|
|
||||||
// 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.
|
||||||
|
|||||||
Reference in New Issue
Block a user