Commit 6ac68d44 authored by David Reid's avatar David Reid

Add support for configuring the channel mixing mode for devices.

This commit also fixes a bug with simple mixing mode.
parent 0a70fc03
...@@ -2618,12 +2618,20 @@ Interleaves a group of deinterleaved buffers. ...@@ -2618,12 +2618,20 @@ Interleaves a group of deinterleaved buffers.
*/ */
MA_API void ma_interleave_pcm_frames(ma_format format, ma_uint32 channels, ma_uint64 frameCount, const void** ppDeinterleavedPCMFrames, void* pInterleavedPCMFrames); MA_API void ma_interleave_pcm_frames(ma_format format, ma_uint32 channels, ma_uint64 frameCount, const void** ppDeinterleavedPCMFrames, void* pInterleavedPCMFrames);
/************************************************************************************************************************************************************ /************************************************************************************************************************************************************
Channel Maps Channel Maps
************************************************************************************************************************************************************/ ************************************************************************************************************************************************************/
/*
Initializes a blank channel map.
When a blank channel map is specified anywhere it indicates that the native channel map should be used.
*/
MA_API void ma_channel_map_init_blank(ma_uint32 channels, ma_channel* pChannelMap);
/* /*
Helper for retrieving a standard channel map. Helper for retrieving a standard channel map.
...@@ -3297,6 +3305,7 @@ struct ma_device_config ...@@ -3297,6 +3305,7 @@ struct ma_device_config
ma_format format; ma_format format;
ma_uint32 channels; ma_uint32 channels;
ma_channel channelMap[MA_MAX_CHANNELS]; ma_channel channelMap[MA_MAX_CHANNELS];
ma_channel_mix_mode channelMixMode;
ma_share_mode shareMode; ma_share_mode shareMode;
} playback; } playback;
struct struct
...@@ -3305,6 +3314,7 @@ struct ma_device_config ...@@ -3305,6 +3314,7 @@ struct ma_device_config
ma_format format; ma_format format;
ma_uint32 channels; ma_uint32 channels;
ma_channel channelMap[MA_MAX_CHANNELS]; ma_channel channelMap[MA_MAX_CHANNELS];
ma_channel_mix_mode channelMixMode;
ma_share_mode shareMode; ma_share_mode shareMode;
} capture; } capture;
...@@ -3948,6 +3958,7 @@ struct ma_device ...@@ -3948,6 +3958,7 @@ struct ma_device
ma_channel internalChannelMap[MA_MAX_CHANNELS]; ma_channel internalChannelMap[MA_MAX_CHANNELS];
ma_uint32 internalPeriodSizeInFrames; ma_uint32 internalPeriodSizeInFrames;
ma_uint32 internalPeriods; ma_uint32 internalPeriods;
ma_channel_mix_mode channelMixMode;
ma_data_converter converter; ma_data_converter converter;
ma_bool8 usingDefaultFormat; ma_bool8 usingDefaultFormat;
ma_bool8 usingDefaultChannels; ma_bool8 usingDefaultChannels;
...@@ -3967,6 +3978,7 @@ struct ma_device ...@@ -3967,6 +3978,7 @@ struct ma_device
ma_channel internalChannelMap[MA_MAX_CHANNELS]; ma_channel internalChannelMap[MA_MAX_CHANNELS];
ma_uint32 internalPeriodSizeInFrames; ma_uint32 internalPeriodSizeInFrames;
ma_uint32 internalPeriods; ma_uint32 internalPeriods;
ma_channel_mix_mode channelMixMode;
ma_data_converter converter; ma_data_converter converter;
ma_bool8 usingDefaultFormat; ma_bool8 usingDefaultFormat;
ma_bool8 usingDefaultChannels; ma_bool8 usingDefaultChannels;
...@@ -31899,11 +31911,15 @@ static ma_result ma_device__post_init_setup(ma_device* pDevice, ma_device_type d ...@@ -31899,11 +31911,15 @@ static ma_result ma_device__post_init_setup(ma_device* pDevice, ma_device_type d
MA_ASSERT(pDevice->capture.channels <= MA_MAX_CHANNELS); MA_ASSERT(pDevice->capture.channels <= MA_MAX_CHANNELS);
if (pDevice->capture.internalChannels == pDevice->capture.channels) { if (pDevice->capture.internalChannels == pDevice->capture.channels) {
ma_channel_map_copy(pDevice->capture.channelMap, pDevice->capture.internalChannelMap, pDevice->capture.channels); ma_channel_map_copy(pDevice->capture.channelMap, pDevice->capture.internalChannelMap, pDevice->capture.channels);
} else {
if (pDevice->capture.channelMixMode == ma_channel_mix_mode_simple) {
ma_channel_map_init_blank(pDevice->capture.channels, pDevice->capture.channelMap);
} else { } else {
ma_get_standard_channel_map(ma_standard_channel_map_default, pDevice->capture.channels, pDevice->capture.channelMap); ma_get_standard_channel_map(ma_standard_channel_map_default, pDevice->capture.channels, pDevice->capture.channelMap);
} }
} }
} }
}
if (deviceType == ma_device_type_playback || deviceType == ma_device_type_duplex) { if (deviceType == ma_device_type_playback || deviceType == ma_device_type_duplex) {
if (pDevice->playback.usingDefaultFormat) { if (pDevice->playback.usingDefaultFormat) {
...@@ -31916,11 +31932,15 @@ static ma_result ma_device__post_init_setup(ma_device* pDevice, ma_device_type d ...@@ -31916,11 +31932,15 @@ static ma_result ma_device__post_init_setup(ma_device* pDevice, ma_device_type d
MA_ASSERT(pDevice->playback.channels <= MA_MAX_CHANNELS); MA_ASSERT(pDevice->playback.channels <= MA_MAX_CHANNELS);
if (pDevice->playback.internalChannels == pDevice->playback.channels) { if (pDevice->playback.internalChannels == pDevice->playback.channels) {
ma_channel_map_copy(pDevice->playback.channelMap, pDevice->playback.internalChannelMap, pDevice->playback.channels); ma_channel_map_copy(pDevice->playback.channelMap, pDevice->playback.internalChannelMap, pDevice->playback.channels);
} else {
if (pDevice->playback.channelMixMode == ma_channel_mix_mode_simple) {
ma_channel_map_init_blank(pDevice->playback.channels, pDevice->playback.channelMap);
} else { } else {
ma_get_standard_channel_map(ma_standard_channel_map_default, pDevice->playback.channels, pDevice->playback.channelMap); ma_get_standard_channel_map(ma_standard_channel_map_default, pDevice->playback.channels, pDevice->playback.channelMap);
} }
} }
} }
}
if (pDevice->usingDefaultSampleRate) { if (pDevice->usingDefaultSampleRate) {
if (deviceType == ma_device_type_capture || deviceType == ma_device_type_duplex) { if (deviceType == ma_device_type_capture || deviceType == ma_device_type_duplex) {
...@@ -31942,6 +31962,7 @@ static ma_result ma_device__post_init_setup(ma_device* pDevice, ma_device_type d ...@@ -31942,6 +31962,7 @@ static ma_result ma_device__post_init_setup(ma_device* pDevice, ma_device_type d
converterConfig.channelsOut = pDevice->capture.channels; converterConfig.channelsOut = pDevice->capture.channels;
converterConfig.sampleRateOut = pDevice->sampleRate; converterConfig.sampleRateOut = pDevice->sampleRate;
ma_channel_map_copy(converterConfig.channelMapOut, pDevice->capture.channelMap, ma_min(pDevice->capture.channels, MA_MAX_CHANNELS)); ma_channel_map_copy(converterConfig.channelMapOut, pDevice->capture.channelMap, ma_min(pDevice->capture.channels, MA_MAX_CHANNELS));
converterConfig.channelMixMode = pDevice->capture.channelMixMode;
converterConfig.resampling.allowDynamicSampleRate = MA_FALSE; converterConfig.resampling.allowDynamicSampleRate = MA_FALSE;
converterConfig.resampling.algorithm = pDevice->resampling.algorithm; converterConfig.resampling.algorithm = pDevice->resampling.algorithm;
converterConfig.resampling.linear.lpfOrder = pDevice->resampling.linear.lpfOrder; converterConfig.resampling.linear.lpfOrder = pDevice->resampling.linear.lpfOrder;
...@@ -31964,6 +31985,7 @@ static ma_result ma_device__post_init_setup(ma_device* pDevice, ma_device_type d ...@@ -31964,6 +31985,7 @@ static ma_result ma_device__post_init_setup(ma_device* pDevice, ma_device_type d
converterConfig.channelsOut = pDevice->playback.internalChannels; converterConfig.channelsOut = pDevice->playback.internalChannels;
converterConfig.sampleRateOut = pDevice->playback.internalSampleRate; converterConfig.sampleRateOut = pDevice->playback.internalSampleRate;
ma_channel_map_copy(converterConfig.channelMapOut, pDevice->playback.internalChannelMap, ma_min(pDevice->playback.internalChannels, MA_MAX_CHANNELS)); ma_channel_map_copy(converterConfig.channelMapOut, pDevice->playback.internalChannelMap, ma_min(pDevice->playback.internalChannels, MA_MAX_CHANNELS));
converterConfig.channelMixMode = pDevice->playback.channelMixMode;
converterConfig.resampling.allowDynamicSampleRate = MA_FALSE; converterConfig.resampling.allowDynamicSampleRate = MA_FALSE;
converterConfig.resampling.algorithm = pDevice->resampling.algorithm; converterConfig.resampling.algorithm = pDevice->resampling.algorithm;
converterConfig.resampling.linear.lpfOrder = pDevice->resampling.linear.lpfOrder; converterConfig.resampling.linear.lpfOrder = pDevice->resampling.linear.lpfOrder;
...@@ -32985,11 +33007,14 @@ MA_API ma_result ma_device_init(ma_context* pContext, const ma_device_config* pC ...@@ -32985,11 +33007,14 @@ MA_API ma_result ma_device_init(ma_context* pContext, const ma_device_config* pC
pDevice->capture.format = config.capture.format; pDevice->capture.format = config.capture.format;
pDevice->capture.channels = config.capture.channels; pDevice->capture.channels = config.capture.channels;
ma_channel_map_copy(pDevice->capture.channelMap, config.capture.channelMap, config.capture.channels); ma_channel_map_copy(pDevice->capture.channelMap, config.capture.channelMap, config.capture.channels);
pDevice->capture.channelMixMode = config.capture.channelMixMode;
pDevice->playback.shareMode = config.playback.shareMode; pDevice->playback.shareMode = config.playback.shareMode;
pDevice->playback.format = config.playback.format; pDevice->playback.format = config.playback.format;
pDevice->playback.channels = config.playback.channels; pDevice->playback.channels = config.playback.channels;
ma_channel_map_copy(pDevice->playback.channelMap, config.playback.channelMap, config.playback.channels); ma_channel_map_copy(pDevice->playback.channelMap, config.playback.channelMap, config.playback.channels);
pDevice->playback.channelMixMode = config.playback.channelMixMode;
/* The internal format, channel count and sample rate can be modified by the backend. */ /* The internal format, channel count and sample rate can be modified by the backend. */
...@@ -39874,8 +39899,24 @@ MA_API ma_result ma_channel_converter_init(const ma_channel_converter_config* pC ...@@ -39874,8 +39899,24 @@ MA_API ma_result ma_channel_converter_init(const ma_channel_converter_config* pC
} }
} break; } break;
case ma_channel_mix_mode_custom_weights:
case ma_channel_mix_mode_simple: case ma_channel_mix_mode_simple:
{
/* In simple mode, excess channels need to be silenced or dropped. */
ma_uint32 iChannel;
for (iChannel = 0; iChannel < ma_min(pConverter->channelsIn, pConverter->channelsOut); iChannel += 1) {
if (pConverter->format == ma_format_f32) {
if (pConverter->weights.f32[iChannel][iChannel] == 0) {
pConverter->weights.f32[iChannel][iChannel] = 1;
}
} else {
if (pConverter->weights.s16[iChannel][iChannel] == 0) {
pConverter->weights.s16[iChannel][iChannel] = ma_channel_converter_float_to_fixed(1);
}
}
}
} break;
case ma_channel_mix_mode_custom_weights:
default: default:
{ {
/* Fallthrough. */ /* Fallthrough. */
...@@ -41235,6 +41276,15 @@ MA_API ma_uint64 ma_data_converter_get_output_latency(ma_data_converter* pConver ...@@ -41235,6 +41276,15 @@ MA_API ma_uint64 ma_data_converter_get_output_latency(ma_data_converter* pConver
Channel Maps Channel Maps
**************************************************************************************************************************************************************/ **************************************************************************************************************************************************************/
MA_API void ma_channel_map_init_blank(ma_uint32 channels, ma_channel* pChannelMap)
{
if (pChannelMap == NULL) {
return;
}
MA_ZERO_MEMORY(pChannelMap, sizeof(*pChannelMap) * channels);
}
static void ma_get_standard_channel_map_microsoft(ma_uint32 channels, ma_channel* pChannelMap) static void ma_get_standard_channel_map_microsoft(ma_uint32 channels, ma_channel* pChannelMap)
{ {
/* Based off the speaker configurations mentioned here: https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/content/ksmedia/ns-ksmedia-ksaudio_channel_config */ /* Based off the speaker configurations mentioned here: https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/content/ksmedia/ns-ksmedia-ksaudio_channel_config */
...@@ -64402,8 +64452,11 @@ The following miscellaneous changes have also been made. ...@@ -64402,8 +64452,11 @@ The following miscellaneous changes have also been made.
REVISION HISTORY REVISION HISTORY
================ ================
v0.10.27 - TBD v0.10.27 - TBD
- Fix some bugs with trying to access uninitialized variables.
- Add support for dynamically configuring some properties of `ma_noise` objects post-initialization. - Add support for dynamically configuring some properties of `ma_noise` objects post-initialization.
- Add support for configuring the channel mixing mode in the device config.
- Fix a bug with simple channel mixing mode (drop or silence excess channels).
- Fix some bugs with trying to access uninitialized variables.
v0.10.26 - 2020-11-24 v0.10.26 - 2020-11-24
- WASAPI: Fix a bug where the exclusive mode format may not be retrieved correctly due to accessing freed memory. - WASAPI: Fix a bug where the exclusive mode format may not be retrieved correctly due to accessing freed memory.
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