Commit b45e2ee5 authored by David Reid's avatar David Reid

Fix some potential buffers overflows with channel mapping.

parent 90b59022
/* /*
Audio playback and capture library. Choice of public domain or MIT-0. See license statements at the end of this file. Audio playback and capture library. Choice of public domain or MIT-0. See license statements at the end of this file.
miniaudio - v0.10.12 - 2020-07-04 miniaudio - v0.10.13 - TBD
David Reid - davidreidsoftware@gmail.com David Reid - davidreidsoftware@gmail.com
...@@ -1372,7 +1372,7 @@ extern "C" { ...@@ -1372,7 +1372,7 @@ extern "C" {
#define MA_VERSION_MAJOR 0 #define MA_VERSION_MAJOR 0
#define MA_VERSION_MINOR 10 #define MA_VERSION_MINOR 10
#define MA_VERSION_REVISION 12 #define MA_VERSION_REVISION 13
#define MA_VERSION_STRING MA_XSTRINGIFY(MA_VERSION_MAJOR) "." MA_XSTRINGIFY(MA_VERSION_MINOR) "." MA_XSTRINGIFY(MA_VERSION_REVISION) #define MA_VERSION_STRING MA_XSTRINGIFY(MA_VERSION_MAJOR) "." MA_XSTRINGIFY(MA_VERSION_MINOR) "." MA_XSTRINGIFY(MA_VERSION_REVISION)
#if defined(_MSC_VER) && !defined(__clang__) #if defined(_MSC_VER) && !defined(__clang__)
...@@ -2430,7 +2430,7 @@ typedef struct ...@@ -2430,7 +2430,7 @@ typedef struct
float weights[MA_MAX_CHANNELS][MA_MAX_CHANNELS]; /* [in][out]. Only used when mixingMode is set to ma_channel_mix_mode_custom_weights. */ float weights[MA_MAX_CHANNELS][MA_MAX_CHANNELS]; /* [in][out]. Only used when mixingMode is set to ma_channel_mix_mode_custom_weights. */
} ma_channel_converter_config; } ma_channel_converter_config;
MA_API ma_channel_converter_config ma_channel_converter_config_init(ma_format format, ma_uint32 channelsIn, const ma_channel channelMapIn[MA_MAX_CHANNELS], ma_uint32 channelsOut, const ma_channel channelMapOut[MA_MAX_CHANNELS], ma_channel_mix_mode mixingMode); MA_API ma_channel_converter_config ma_channel_converter_config_init(ma_format format, ma_uint32 channelsIn, const ma_channel* pChannelMapIn, ma_uint32 channelsOut, const ma_channel* pChannelMapOut, ma_channel_mix_mode mixingMode);
typedef struct typedef struct
{ {
...@@ -2563,11 +2563,15 @@ Channel Maps ...@@ -2563,11 +2563,15 @@ Channel Maps
/* /*
Helper for retrieving a standard channel map. Helper for retrieving a standard channel map.
The output channel map buffer must have a capacity of at least `channels`.
*/ */
MA_API void ma_get_standard_channel_map(ma_standard_channel_map standardChannelMap, ma_uint32 channels, ma_channel channelMap[MA_MAX_CHANNELS]); MA_API void ma_get_standard_channel_map(ma_standard_channel_map standardChannelMap, ma_uint32 channels, ma_channel* pChannelMap);
/* /*
Copies a channel map. Copies a channel map.
Both input and output channel map buffers must have a capacity of at at least `channels`.
*/ */
MA_API void ma_channel_map_copy(ma_channel* pOut, const ma_channel* pIn, ma_uint32 channels); MA_API void ma_channel_map_copy(ma_channel* pOut, const ma_channel* pIn, ma_uint32 channels);
...@@ -2581,25 +2585,33 @@ is usually treated as a passthrough. ...@@ -2581,25 +2585,33 @@ is usually treated as a passthrough.
Invalid channel maps: Invalid channel maps:
- A channel map with no channels - A channel map with no channels
- A channel map with more than one channel and a mono channel - A channel map with more than one channel and a mono channel
The channel map buffer must have a capacity of at least `channels`.
*/ */
MA_API ma_bool32 ma_channel_map_valid(ma_uint32 channels, const ma_channel channelMap[MA_MAX_CHANNELS]); MA_API ma_bool32 ma_channel_map_valid(ma_uint32 channels, const ma_channel* pChannelMap);
/* /*
Helper for comparing two channel maps for equality. Helper for comparing two channel maps for equality.
This assumes the channel count is the same between the two. This assumes the channel count is the same between the two.
Both channels map buffers must have a capacity of at least `channels`.
*/ */
MA_API ma_bool32 ma_channel_map_equal(ma_uint32 channels, const ma_channel channelMapA[MA_MAX_CHANNELS], const ma_channel channelMapB[MA_MAX_CHANNELS]); MA_API ma_bool32 ma_channel_map_equal(ma_uint32 channels, const ma_channel* pChannelMapA, const ma_channel* pChannelMapB);
/* /*
Helper for determining if a channel map is blank (all channels set to MA_CHANNEL_NONE). Helper for determining if a channel map is blank (all channels set to MA_CHANNEL_NONE).
The channel map buffer must have a capacity of at least `channels`.
*/ */
MA_API ma_bool32 ma_channel_map_blank(ma_uint32 channels, const ma_channel channelMap[MA_MAX_CHANNELS]); MA_API ma_bool32 ma_channel_map_blank(ma_uint32 channels, const ma_channel* pChannelMap);
/* /*
Helper for determining whether or not a channel is present in the given channel map. Helper for determining whether or not a channel is present in the given channel map.
The channel map buffer must have a capacity of at least `channels`.
*/ */
MA_API ma_bool32 ma_channel_map_contains_channel_position(ma_uint32 channels, const ma_channel channelMap[MA_MAX_CHANNELS], ma_channel channelPosition); MA_API ma_bool32 ma_channel_map_contains_channel_position(ma_uint32 channels, const ma_channel* pChannelMap, ma_channel channelPosition);
/************************************************************************************************************************************************************ /************************************************************************************************************************************************************
...@@ -10488,7 +10500,7 @@ static ma_result ma_device_init__null(ma_context* pContext, const ma_device_conf ...@@ -10488,7 +10500,7 @@ static ma_result ma_device_init__null(ma_context* pContext, const ma_device_conf
ma_strncpy_s(pDevice->capture.name, sizeof(pDevice->capture.name), "NULL Capture Device", (size_t)-1); ma_strncpy_s(pDevice->capture.name, sizeof(pDevice->capture.name), "NULL Capture Device", (size_t)-1);
pDevice->capture.internalFormat = pConfig->capture.format; pDevice->capture.internalFormat = pConfig->capture.format;
pDevice->capture.internalChannels = pConfig->capture.channels; pDevice->capture.internalChannels = pConfig->capture.channels;
ma_channel_map_copy(pDevice->capture.internalChannelMap, pConfig->capture.channelMap, pConfig->capture.channels); ma_channel_map_copy(pDevice->capture.internalChannelMap, pConfig->capture.channelMap, ma_min(pConfig->capture.channels, MA_MAX_CHANNELS));
pDevice->capture.internalPeriodSizeInFrames = periodSizeInFrames; pDevice->capture.internalPeriodSizeInFrames = periodSizeInFrames;
pDevice->capture.internalPeriods = pConfig->periods; pDevice->capture.internalPeriods = pConfig->periods;
} }
...@@ -10496,7 +10508,7 @@ static ma_result ma_device_init__null(ma_context* pContext, const ma_device_conf ...@@ -10496,7 +10508,7 @@ static ma_result ma_device_init__null(ma_context* pContext, const ma_device_conf
ma_strncpy_s(pDevice->playback.name, sizeof(pDevice->playback.name), "NULL Playback Device", (size_t)-1); ma_strncpy_s(pDevice->playback.name, sizeof(pDevice->playback.name), "NULL Playback Device", (size_t)-1);
pDevice->playback.internalFormat = pConfig->playback.format; pDevice->playback.internalFormat = pConfig->playback.format;
pDevice->playback.internalChannels = pConfig->playback.channels; pDevice->playback.internalChannels = pConfig->playback.channels;
ma_channel_map_copy(pDevice->playback.internalChannelMap, pConfig->playback.channelMap, pConfig->playback.channels); ma_channel_map_copy(pDevice->playback.internalChannelMap, pConfig->playback.channelMap, ma_min(pConfig->playback.channels, MA_MAX_CHANNELS));
pDevice->playback.internalPeriodSizeInFrames = periodSizeInFrames; pDevice->playback.internalPeriodSizeInFrames = periodSizeInFrames;
pDevice->playback.internalPeriods = pConfig->periods; pDevice->playback.internalPeriods = pConfig->periods;
} }
...@@ -11045,39 +11057,39 @@ static DWORD ma_channel_id_to_win32(DWORD id) ...@@ -11045,39 +11057,39 @@ static DWORD ma_channel_id_to_win32(DWORD id)
} }
/* Converts a channel mapping to a Win32-style channel mask. */ /* Converts a channel mapping to a Win32-style channel mask. */
static DWORD ma_channel_map_to_channel_mask__win32(const ma_channel channelMap[MA_MAX_CHANNELS], ma_uint32 channels) static DWORD ma_channel_map_to_channel_mask__win32(const ma_channel* pChannelMap, ma_uint32 channels)
{ {
DWORD dwChannelMask = 0; DWORD dwChannelMask = 0;
ma_uint32 iChannel; ma_uint32 iChannel;
for (iChannel = 0; iChannel < channels; ++iChannel) { for (iChannel = 0; iChannel < channels; ++iChannel) {
dwChannelMask |= ma_channel_id_to_win32(channelMap[iChannel]); dwChannelMask |= ma_channel_id_to_win32(pChannelMap[iChannel]);
} }
return dwChannelMask; return dwChannelMask;
} }
/* Converts a Win32-style channel mask to a miniaudio channel map. */ /* Converts a Win32-style channel mask to a miniaudio channel map. */
static void ma_channel_mask_to_channel_map__win32(DWORD dwChannelMask, ma_uint32 channels, ma_channel channelMap[MA_MAX_CHANNELS]) static void ma_channel_mask_to_channel_map__win32(DWORD dwChannelMask, ma_uint32 channels, ma_channel* pChannelMap)
{ {
if (channels == 1 && dwChannelMask == 0) { if (channels == 1 && dwChannelMask == 0) {
channelMap[0] = MA_CHANNEL_MONO; pChannelMap[0] = MA_CHANNEL_MONO;
} else if (channels == 2 && dwChannelMask == 0) { } else if (channels == 2 && dwChannelMask == 0) {
channelMap[0] = MA_CHANNEL_FRONT_LEFT; pChannelMap[0] = MA_CHANNEL_FRONT_LEFT;
channelMap[1] = MA_CHANNEL_FRONT_RIGHT; pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT;
} else { } else {
if (channels == 1 && (dwChannelMask & SPEAKER_FRONT_CENTER) != 0) { if (channels == 1 && (dwChannelMask & SPEAKER_FRONT_CENTER) != 0) {
channelMap[0] = MA_CHANNEL_MONO; pChannelMap[0] = MA_CHANNEL_MONO;
} else { } else {
/* Just iterate over each bit. */ /* Just iterate over each bit. */
ma_uint32 iChannel = 0; ma_uint32 iChannel = 0;
ma_uint32 iBit; ma_uint32 iBit;
for (iBit = 0; iBit < 32; ++iBit) { for (iBit = 0; iBit < 32 && iBit < channels; ++iBit) {
DWORD bitValue = (dwChannelMask & (1UL << iBit)); DWORD bitValue = (dwChannelMask & (1UL << iBit));
if (bitValue != 0) { if (bitValue != 0) {
/* The bit is set. */ /* The bit is set. */
channelMap[iChannel] = ma_channel_id_to_ma__win32(bitValue); pChannelMap[iChannel] = ma_channel_id_to_ma__win32(bitValue);
iChannel += 1; iChannel += 1;
} }
} }
...@@ -12008,6 +12020,11 @@ static ma_result ma_context_get_device_info_from_IAudioClient__wasapi(ma_context ...@@ -12008,6 +12020,11 @@ static ma_result ma_context_get_device_info_from_IAudioClient__wasapi(ma_context
ma_bool32 found; ma_bool32 found;
ma_uint32 iFormat; ma_uint32 iFormat;
/* Make sure we don't overflow the channel map. */
if (channels > MA_MAX_CHANNELS) {
channels = MA_MAX_CHANNELS;
}
ma_get_standard_channel_map(ma_standard_channel_map_microsoft, channels, defaultChannelMap); ma_get_standard_channel_map(ma_standard_channel_map_microsoft, channels, defaultChannelMap);
MA_ZERO_OBJECT(&wf); MA_ZERO_OBJECT(&wf);
...@@ -18752,7 +18769,7 @@ static ma_result ma_device_init_by_type__alsa(ma_context* pContext, const ma_dev ...@@ -18752,7 +18769,7 @@ static ma_result ma_device_init_by_type__alsa(ma_context* pContext, const ma_dev
pDevice->capture.internalFormat = internalFormat; pDevice->capture.internalFormat = internalFormat;
pDevice->capture.internalChannels = internalChannels; pDevice->capture.internalChannels = internalChannels;
pDevice->capture.internalSampleRate = internalSampleRate; pDevice->capture.internalSampleRate = internalSampleRate;
ma_channel_map_copy(pDevice->capture.internalChannelMap, internalChannelMap, internalChannels); ma_channel_map_copy(pDevice->capture.internalChannelMap, internalChannelMap, ma_min(internalChannels, MA_MAX_CHANNELS));
pDevice->capture.internalPeriodSizeInFrames = internalPeriodSizeInFrames; pDevice->capture.internalPeriodSizeInFrames = internalPeriodSizeInFrames;
pDevice->capture.internalPeriods = internalPeriods; pDevice->capture.internalPeriods = internalPeriods;
} else { } else {
...@@ -18761,7 +18778,7 @@ static ma_result ma_device_init_by_type__alsa(ma_context* pContext, const ma_dev ...@@ -18761,7 +18778,7 @@ static ma_result ma_device_init_by_type__alsa(ma_context* pContext, const ma_dev
pDevice->playback.internalFormat = internalFormat; pDevice->playback.internalFormat = internalFormat;
pDevice->playback.internalChannels = internalChannels; pDevice->playback.internalChannels = internalChannels;
pDevice->playback.internalSampleRate = internalSampleRate; pDevice->playback.internalSampleRate = internalSampleRate;
ma_channel_map_copy(pDevice->playback.internalChannelMap, internalChannelMap, internalChannels); ma_channel_map_copy(pDevice->playback.internalChannelMap, internalChannelMap, ma_min(internalChannels, MA_MAX_CHANNELS));
pDevice->playback.internalPeriodSizeInFrames = internalPeriodSizeInFrames; pDevice->playback.internalPeriodSizeInFrames = internalPeriodSizeInFrames;
pDevice->playback.internalPeriods = internalPeriods; pDevice->playback.internalPeriods = internalPeriods;
} }
...@@ -22637,14 +22654,14 @@ static ma_channel ma_channel_from_AudioChannelLabel(AudioChannelLabel label) ...@@ -22637,14 +22654,14 @@ static ma_channel ma_channel_from_AudioChannelLabel(AudioChannelLabel label)
} }
} }
static ma_result ma_get_channel_map_from_AudioChannelLayout(AudioChannelLayout* pChannelLayout, ma_channel channelMap[MA_MAX_CHANNELS]) static ma_result ma_get_channel_map_from_AudioChannelLayout(AudioChannelLayout* pChannelLayout, ma_channel* pChannelMap, size_t channelMapCap)
{ {
MA_ASSERT(pChannelLayout != NULL); MA_ASSERT(pChannelLayout != NULL);
if (pChannelLayout->mChannelLayoutTag == kAudioChannelLayoutTag_UseChannelDescriptions) { if (pChannelLayout->mChannelLayoutTag == kAudioChannelLayoutTag_UseChannelDescriptions) {
UInt32 iChannel; UInt32 iChannel;
for (iChannel = 0; iChannel < pChannelLayout->mNumberChannelDescriptions; ++iChannel) { for (iChannel = 0; iChannel < pChannelLayout->mNumberChannelDescriptions && iChannel < channelMapCap; ++iChannel) {
channelMap[iChannel] = ma_channel_from_AudioChannelLabel(pChannelLayout->mChannelDescriptions[iChannel].mChannelLabel); pChannelMap[iChannel] = ma_channel_from_AudioChannelLabel(pChannelLayout->mChannelDescriptions[iChannel].mChannelLabel);
} }
} else } else
#if 0 #if 0
...@@ -22653,10 +22670,10 @@ static ma_result ma_get_channel_map_from_AudioChannelLayout(AudioChannelLayout* ...@@ -22653,10 +22670,10 @@ static ma_result ma_get_channel_map_from_AudioChannelLayout(AudioChannelLayout*
UInt32 iChannel = 0; UInt32 iChannel = 0;
UInt32 iBit; UInt32 iBit;
AudioChannelBitmap bitmap = pChannelLayout->mChannelBitmap; AudioChannelBitmap bitmap = pChannelLayout->mChannelBitmap;
for (iBit = 0; iBit < 32; ++iBit) { for (iBit = 0; iBit < 32 && iBit < channelMapCap; ++iBit) {
AudioChannelBitmap bit = bitmap & (1 << iBit); AudioChannelBitmap bit = bitmap & (1 << iBit);
if (bit != 0) { if (bit != 0) {
channelMap[iChannel++] = ma_channel_from_AudioChannelBit(bit); pChannelMap[iChannel++] = ma_channel_from_AudioChannelBit(bit);
} }
} }
} else } else
...@@ -22666,7 +22683,8 @@ static ma_result ma_get_channel_map_from_AudioChannelLayout(AudioChannelLayout* ...@@ -22666,7 +22683,8 @@ static ma_result ma_get_channel_map_from_AudioChannelLayout(AudioChannelLayout*
Need to use the tag to determine the channel map. For now I'm just assuming a default channel map, but later on this should Need to use the tag to determine the channel map. For now I'm just assuming a default channel map, but later on this should
be updated to determine the mapping based on the tag. be updated to determine the mapping based on the tag.
*/ */
UInt32 channelCount = AudioChannelLayoutTag_GetNumberOfChannels(pChannelLayout->mChannelLayoutTag); UInt32 channelCount = ma_min(AudioChannelLayoutTag_GetNumberOfChannels(pChannelLayout->mChannelLayoutTag), channelMapCap);
switch (pChannelLayout->mChannelLayoutTag) switch (pChannelLayout->mChannelLayoutTag)
{ {
case kAudioChannelLayoutTag_Mono: case kAudioChannelLayoutTag_Mono:
...@@ -22678,35 +22696,35 @@ static ma_result ma_get_channel_map_from_AudioChannelLayout(AudioChannelLayout* ...@@ -22678,35 +22696,35 @@ static ma_result ma_get_channel_map_from_AudioChannelLayout(AudioChannelLayout*
case kAudioChannelLayoutTag_Binaural: case kAudioChannelLayoutTag_Binaural:
case kAudioChannelLayoutTag_Ambisonic_B_Format: case kAudioChannelLayoutTag_Ambisonic_B_Format:
{ {
ma_get_standard_channel_map(ma_standard_channel_map_default, channelCount, channelMap); ma_get_standard_channel_map(ma_standard_channel_map_default, channelCount, pChannelMap);
} break; } break;
case kAudioChannelLayoutTag_Octagonal: case kAudioChannelLayoutTag_Octagonal:
{ {
channelMap[7] = MA_CHANNEL_SIDE_RIGHT; pChannelMap[7] = MA_CHANNEL_SIDE_RIGHT;
channelMap[6] = MA_CHANNEL_SIDE_LEFT; pChannelMap[6] = MA_CHANNEL_SIDE_LEFT;
} /* Intentional fallthrough. */ } /* Intentional fallthrough. */
case kAudioChannelLayoutTag_Hexagonal: case kAudioChannelLayoutTag_Hexagonal:
{ {
channelMap[5] = MA_CHANNEL_BACK_CENTER; pChannelMap[5] = MA_CHANNEL_BACK_CENTER;
} /* Intentional fallthrough. */ } /* Intentional fallthrough. */
case kAudioChannelLayoutTag_Pentagonal: case kAudioChannelLayoutTag_Pentagonal:
{ {
channelMap[4] = MA_CHANNEL_FRONT_CENTER; pChannelMap[4] = MA_CHANNEL_FRONT_CENTER;
} /* Intentional fallghrough. */ } /* Intentional fallghrough. */
case kAudioChannelLayoutTag_Quadraphonic: case kAudioChannelLayoutTag_Quadraphonic:
{ {
channelMap[3] = MA_CHANNEL_BACK_RIGHT; pChannelMap[3] = MA_CHANNEL_BACK_RIGHT;
channelMap[2] = MA_CHANNEL_BACK_LEFT; pChannelMap[2] = MA_CHANNEL_BACK_LEFT;
channelMap[1] = MA_CHANNEL_RIGHT; pChannelMap[1] = MA_CHANNEL_RIGHT;
channelMap[0] = MA_CHANNEL_LEFT; pChannelMap[0] = MA_CHANNEL_LEFT;
} break; } break;
/* TODO: Add support for more tags here. */ /* TODO: Add support for more tags here. */
default: default:
{ {
ma_get_standard_channel_map(ma_standard_channel_map_default, channelCount, channelMap); ma_get_standard_channel_map(ma_standard_channel_map_default, channelCount, pChannelMap);
} break; } break;
} }
} }
...@@ -22979,7 +22997,7 @@ static ma_result ma_get_AudioObject_channel_count(ma_context* pContext, AudioObj ...@@ -22979,7 +22997,7 @@ static ma_result ma_get_AudioObject_channel_count(ma_context* pContext, AudioObj
} }
#if 0 #if 0
static ma_result ma_get_AudioObject_channel_map(ma_context* pContext, AudioObjectID deviceObjectID, ma_device_type deviceType, ma_channel channelMap[MA_MAX_CHANNELS]) static ma_result ma_get_AudioObject_channel_map(ma_context* pContext, AudioObjectID deviceObjectID, ma_device_type deviceType, ma_channel* pChannelMap, size_t channelMapCap)
{ {
AudioChannelLayout* pChannelLayout; AudioChannelLayout* pChannelLayout;
ma_result result; ma_result result;
...@@ -22991,7 +23009,7 @@ static ma_result ma_get_AudioObject_channel_map(ma_context* pContext, AudioObjec ...@@ -22991,7 +23009,7 @@ static ma_result ma_get_AudioObject_channel_map(ma_context* pContext, AudioObjec
return result; /* Rather than always failing here, would it be more robust to simply assume a default? */ return result; /* Rather than always failing here, would it be more robust to simply assume a default? */
} }
result = ma_get_channel_map_from_AudioChannelLayout(pChannelLayout, channelMap); result = ma_get_channel_map_from_AudioChannelLayout(pChannelLayout, pChannelMap, channelMapCap);
if (result != MA_SUCCESS) { if (result != MA_SUCCESS) {
ma_free(pChannelLayout, &pContext->allocationCallbacks); ma_free(pChannelLayout, &pContext->allocationCallbacks);
return result; return result;
...@@ -23471,7 +23489,7 @@ static ma_result ma_find_best_format__coreaudio(ma_context* pContext, AudioObjec ...@@ -23471,7 +23489,7 @@ static ma_result ma_find_best_format__coreaudio(ma_context* pContext, AudioObjec
return MA_SUCCESS; return MA_SUCCESS;
} }
static ma_result ma_get_AudioUnit_channel_map(ma_context* pContext, AudioUnit audioUnit, ma_device_type deviceType, ma_channel channelMap[MA_MAX_CHANNELS]) static ma_result ma_get_AudioUnit_channel_map(ma_context* pContext, AudioUnit audioUnit, ma_device_type deviceType, ma_channel* pChannelMap, size_t channelMapCap)
{ {
AudioUnitScope deviceScope; AudioUnitScope deviceScope;
AudioUnitElement deviceBus; AudioUnitElement deviceBus;
...@@ -23506,7 +23524,7 @@ static ma_result ma_get_AudioUnit_channel_map(ma_context* pContext, AudioUnit au ...@@ -23506,7 +23524,7 @@ static ma_result ma_get_AudioUnit_channel_map(ma_context* pContext, AudioUnit au
return ma_result_from_OSStatus(status); return ma_result_from_OSStatus(status);
} }
result = ma_get_channel_map_from_AudioChannelLayout(pChannelLayout, channelMap); result = ma_get_channel_map_from_AudioChannelLayout(pChannelLayout, pChannelMap, channelMapCap);
if (result != MA_SUCCESS) { if (result != MA_SUCCESS) {
ma__free_from_callbacks(pChannelLayout, &pContext->allocationCallbacks); ma__free_from_callbacks(pChannelLayout, &pContext->allocationCallbacks);
return result; return result;
...@@ -23813,6 +23831,7 @@ static OSStatus ma_on_output__coreaudio(void* pUserData, AudioUnitRenderActionFl ...@@ -23813,6 +23831,7 @@ static OSStatus ma_on_output__coreaudio(void* pUserData, AudioUnitRenderActionFl
} }
} else { } else {
/* This is the deinterleaved case. We need to update each buffer in groups of internalChannels. This assumes each buffer is the same size. */ /* This is the deinterleaved case. We need to update each buffer in groups of internalChannels. This assumes each buffer is the same size. */
MA_ASSERT(pDevice->playback.internalChannels <= MA_MAX_CHANNELS); /* This should heve been validated at initialization time. */
/* /*
For safety we'll check that the internal channels is a multiple of the buffer count. If it's not it means something For safety we'll check that the internal channels is a multiple of the buffer count. If it's not it means something
...@@ -23935,6 +23954,7 @@ static OSStatus ma_on_input__coreaudio(void* pUserData, AudioUnitRenderActionFla ...@@ -23935,6 +23954,7 @@ static OSStatus ma_on_input__coreaudio(void* pUserData, AudioUnitRenderActionFla
} }
} else { } else {
/* This is the deinterleaved case. We need to interleave the audio data before sending it to the client. This assumes each buffer is the same size. */ /* This is the deinterleaved case. We need to interleave the audio data before sending it to the client. This assumes each buffer is the same size. */
MA_ASSERT(pDevice->capture.internalChannels <= MA_MAX_CHANNELS); /* This should have been validated at initialization time. */
/* /*
For safety we'll check that the internal channels is a multiple of the buffer count. If it's not it means something For safety we'll check that the internal channels is a multiple of the buffer count. If it's not it means something
...@@ -24601,6 +24621,11 @@ static ma_result ma_device_init_internal__coreaudio(ma_context* pContext, ma_dev ...@@ -24601,6 +24621,11 @@ static ma_result ma_device_init_internal__coreaudio(ma_context* pContext, ma_dev
pData->channelsOut = bestFormat.mChannelsPerFrame; pData->channelsOut = bestFormat.mChannelsPerFrame;
pData->sampleRateOut = bestFormat.mSampleRate; pData->sampleRateOut = bestFormat.mSampleRate;
} }
/* Clamp the channel count for safety. */
if (pData->channelsOut > MA_MAX_CHANNELS) {
pData->channelsOut = MA_MAX_CHANNELS;
}
/* /*
Internal channel map. This is weird in my testing. If I use the AudioObject to get the Internal channel map. This is weird in my testing. If I use the AudioObject to get the
...@@ -24610,11 +24635,11 @@ static ma_result ma_device_init_internal__coreaudio(ma_context* pContext, ma_dev ...@@ -24610,11 +24635,11 @@ static ma_result ma_device_init_internal__coreaudio(ma_context* pContext, ma_dev
I'm going to fall back to a default assumption in these cases. I'm going to fall back to a default assumption in these cases.
*/ */
#if defined(MA_APPLE_DESKTOP) #if defined(MA_APPLE_DESKTOP)
result = ma_get_AudioUnit_channel_map(pContext, pData->audioUnit, deviceType, pData->channelMapOut); result = ma_get_AudioUnit_channel_map(pContext, pData->audioUnit, deviceType, pData->channelMapOut, pData->channelsOut);
if (result != MA_SUCCESS) { if (result != MA_SUCCESS) {
#if 0 #if 0
/* Try falling back to the channel map from the AudioObject. */ /* Try falling back to the channel map from the AudioObject. */
result = ma_get_AudioObject_channel_map(pContext, deviceObjectID, deviceType, pData->channelMapOut); result = ma_get_AudioObject_channel_map(pContext, deviceObjectID, deviceType, pData->channelMapOut, pData->channelsOut);
if (result != MA_SUCCESS) { if (result != MA_SUCCESS) {
return result; return result;
} }
...@@ -28792,7 +28817,7 @@ static SLuint32 ma_channel_id_to_opensl(ma_uint8 id) ...@@ -28792,7 +28817,7 @@ static SLuint32 ma_channel_id_to_opensl(ma_uint8 id)
} }
/* Converts a channel mapping to an OpenSL-style channel mask. */ /* Converts a channel mapping to an OpenSL-style channel mask. */
static SLuint32 ma_channel_map_to_channel_mask__opensl(const ma_channel channelMap[MA_MAX_CHANNELS], ma_uint32 channels) static SLuint32 ma_channel_map_to_channel_mask__opensl(const ma_channel* pChannelMap, ma_uint32 channels)
{ {
SLuint32 channelMask = 0; SLuint32 channelMask = 0;
ma_uint32 iChannel; ma_uint32 iChannel;
...@@ -28804,7 +28829,7 @@ static SLuint32 ma_channel_map_to_channel_mask__opensl(const ma_channel channelM ...@@ -28804,7 +28829,7 @@ static SLuint32 ma_channel_map_to_channel_mask__opensl(const ma_channel channelM
} }
/* Converts an OpenSL-style channel mask to a miniaudio channel map. */ /* Converts an OpenSL-style channel mask to a miniaudio channel map. */
static void ma_channel_mask_to_channel_map__opensl(SLuint32 channelMask, ma_uint32 channels, ma_channel channelMap[MA_MAX_CHANNELS]) static void ma_channel_mask_to_channel_map__opensl(SLuint32 channelMask, ma_uint32 channels, ma_channel* pChannelMap)
{ {
if (channels == 1 && channelMask == 0) { if (channels == 1 && channelMask == 0) {
channelMap[0] = MA_CHANNEL_MONO; channelMap[0] = MA_CHANNEL_MONO;
...@@ -28818,7 +28843,7 @@ static void ma_channel_mask_to_channel_map__opensl(SLuint32 channelMask, ma_uint ...@@ -28818,7 +28843,7 @@ static void ma_channel_mask_to_channel_map__opensl(SLuint32 channelMask, ma_uint
/* Just iterate over each bit. */ /* Just iterate over each bit. */
ma_uint32 iChannel = 0; ma_uint32 iChannel = 0;
ma_uint32 iBit; ma_uint32 iBit;
for (iBit = 0; iBit < 32; ++iBit) { for (iBit = 0; iBit < 32 && iBit < channels; ++iBit) {
SLuint32 bitValue = (channelMask & (1UL << iBit)); SLuint32 bitValue = (channelMask & (1UL << iBit));
if (bitValue != 0) { if (bitValue != 0) {
/* The bit is set. */ /* The bit is set. */
...@@ -29270,7 +29295,7 @@ static ma_result ma_SLDataFormat_PCM_init__opensl(ma_format format, ma_uint32 ch ...@@ -29270,7 +29295,7 @@ static ma_result ma_SLDataFormat_PCM_init__opensl(ma_format format, ma_uint32 ch
return MA_SUCCESS; return MA_SUCCESS;
} }
static ma_result ma_deconstruct_SLDataFormat_PCM__opensl(ma_SLDataFormat_PCM* pDataFormat, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap) static ma_result ma_deconstruct_SLDataFormat_PCM__opensl(ma_SLDataFormat_PCM* pDataFormat, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap)
{ {
ma_bool32 isFloatingPoint = MA_FALSE; ma_bool32 isFloatingPoint = MA_FALSE;
#if defined(MA_ANDROID) && __ANDROID_API__ >= 21 #if defined(MA_ANDROID) && __ANDROID_API__ >= 21
...@@ -29297,7 +29322,7 @@ static ma_result ma_deconstruct_SLDataFormat_PCM__opensl(ma_SLDataFormat_PCM* pD ...@@ -29297,7 +29322,7 @@ static ma_result ma_deconstruct_SLDataFormat_PCM__opensl(ma_SLDataFormat_PCM* pD
*pChannels = pDataFormat->numChannels; *pChannels = pDataFormat->numChannels;
*pSampleRate = ((SLDataFormat_PCM*)pDataFormat)->samplesPerSec / 1000; *pSampleRate = ((SLDataFormat_PCM*)pDataFormat)->samplesPerSec / 1000;
ma_channel_mask_to_channel_map__opensl(pDataFormat->channelMask, pDataFormat->numChannels, pChannelMap); ma_channel_mask_to_channel_map__opensl(pDataFormat->channelMask, ma_min(pDataFormat->numChannels, channelMapCap), pChannelMap);
return MA_SUCCESS; return MA_SUCCESS;
} }
...@@ -29405,7 +29430,7 @@ static ma_result ma_device_init__opensl(ma_context* pContext, const ma_device_co ...@@ -29405,7 +29430,7 @@ static ma_result ma_device_init__opensl(ma_context* pContext, const ma_device_co
} }
/* The internal format is determined by the "pcm" object. */ /* The internal format is determined by the "pcm" object. */
ma_deconstruct_SLDataFormat_PCM__opensl(&pcm, &pDevice->capture.internalFormat, &pDevice->capture.internalChannels, &pDevice->capture.internalSampleRate, pDevice->capture.internalChannelMap); ma_deconstruct_SLDataFormat_PCM__opensl(&pcm, &pDevice->capture.internalFormat, &pDevice->capture.internalChannels, &pDevice->capture.internalSampleRate, pDevice->capture.internalChannelMap, ma_countof(pDevice->capture.internalChannelMap));
/* Buffer. */ /* Buffer. */
periodSizeInFrames = pConfig->periodSizeInFrames; periodSizeInFrames = pConfig->periodSizeInFrames;
...@@ -29508,7 +29533,7 @@ static ma_result ma_device_init__opensl(ma_context* pContext, const ma_device_co ...@@ -29508,7 +29533,7 @@ static ma_result ma_device_init__opensl(ma_context* pContext, const ma_device_co
} }
/* The internal format is determined by the "pcm" object. */ /* The internal format is determined by the "pcm" object. */
ma_deconstruct_SLDataFormat_PCM__opensl(&pcm, &pDevice->playback.internalFormat, &pDevice->playback.internalChannels, &pDevice->playback.internalSampleRate, pDevice->playback.internalChannelMap); ma_deconstruct_SLDataFormat_PCM__opensl(&pcm, &pDevice->playback.internalFormat, &pDevice->playback.internalChannels, &pDevice->playback.internalSampleRate, pDevice->playback.internalChannelMap, ma_countof(pDevice->playback.internalChannelMap));
/* Buffer. */ /* Buffer. */
periodSizeInFrames = pConfig->periodSizeInFrames; periodSizeInFrames = pConfig->periodSizeInFrames;
...@@ -30357,8 +30382,8 @@ static ma_bool32 ma__is_channel_map_valid(const ma_channel* channelMap, ma_uint3 ...@@ -30357,8 +30382,8 @@ static ma_bool32 ma__is_channel_map_valid(const ma_channel* channelMap, ma_uint3
if (channelMap[0] != MA_CHANNEL_NONE) { if (channelMap[0] != MA_CHANNEL_NONE) {
ma_uint32 iChannel; ma_uint32 iChannel;
if (channels == 0) { if (channels == 0 || channels > MA_MAX_CHANNELS) {
return MA_FALSE; /* No channels. */ return MA_FALSE; /* Channel count out of range. */
} }
/* A channel cannot be present in the channel map more than once. */ /* A channel cannot be present in the channel map more than once. */
...@@ -30390,6 +30415,7 @@ static ma_result ma_device__post_init_setup(ma_device* pDevice, ma_device_type d ...@@ -30390,6 +30415,7 @@ static ma_result ma_device__post_init_setup(ma_device* pDevice, ma_device_type d
pDevice->capture.channels = pDevice->capture.internalChannels; pDevice->capture.channels = pDevice->capture.internalChannels;
} }
if (pDevice->capture.usingDefaultChannelMap) { if (pDevice->capture.usingDefaultChannelMap) {
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 { } else {
...@@ -30406,6 +30432,7 @@ static ma_result ma_device__post_init_setup(ma_device* pDevice, ma_device_type d ...@@ -30406,6 +30432,7 @@ static ma_result ma_device__post_init_setup(ma_device* pDevice, ma_device_type d
pDevice->playback.channels = pDevice->playback.internalChannels; pDevice->playback.channels = pDevice->playback.internalChannels;
} }
if (pDevice->playback.usingDefaultChannelMap) { if (pDevice->playback.usingDefaultChannelMap) {
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 { } else {
...@@ -30422,18 +30449,18 @@ static ma_result ma_device__post_init_setup(ma_device* pDevice, ma_device_type d ...@@ -30422,18 +30449,18 @@ static ma_result ma_device__post_init_setup(ma_device* pDevice, ma_device_type d
} }
} }
/* PCM converters. */ /* Data converters. */
if (deviceType == ma_device_type_capture || deviceType == ma_device_type_duplex || deviceType == ma_device_type_loopback) { if (deviceType == ma_device_type_capture || deviceType == ma_device_type_duplex || deviceType == ma_device_type_loopback) {
/* Converting from internal device format to client format. */ /* Converting from internal device format to client format. */
ma_data_converter_config converterConfig = ma_data_converter_config_init_default(); ma_data_converter_config converterConfig = ma_data_converter_config_init_default();
converterConfig.formatIn = pDevice->capture.internalFormat; converterConfig.formatIn = pDevice->capture.internalFormat;
converterConfig.channelsIn = pDevice->capture.internalChannels; converterConfig.channelsIn = pDevice->capture.internalChannels;
converterConfig.sampleRateIn = pDevice->capture.internalSampleRate; converterConfig.sampleRateIn = pDevice->capture.internalSampleRate;
ma_channel_map_copy(converterConfig.channelMapIn, pDevice->capture.internalChannelMap, pDevice->capture.internalChannels); ma_channel_map_copy(converterConfig.channelMapIn, pDevice->capture.internalChannelMap, ma_min(pDevice->capture.internalChannels, MA_MAX_CHANNELS));
converterConfig.formatOut = pDevice->capture.format; converterConfig.formatOut = pDevice->capture.format;
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, pDevice->capture.channels); ma_channel_map_copy(converterConfig.channelMapOut, pDevice->capture.channelMap, ma_min(pDevice->capture.channels, MA_MAX_CHANNELS));
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;
...@@ -30451,11 +30478,11 @@ static ma_result ma_device__post_init_setup(ma_device* pDevice, ma_device_type d ...@@ -30451,11 +30478,11 @@ static ma_result ma_device__post_init_setup(ma_device* pDevice, ma_device_type d
converterConfig.formatIn = pDevice->playback.format; converterConfig.formatIn = pDevice->playback.format;
converterConfig.channelsIn = pDevice->playback.channels; converterConfig.channelsIn = pDevice->playback.channels;
converterConfig.sampleRateIn = pDevice->sampleRate; converterConfig.sampleRateIn = pDevice->sampleRate;
ma_channel_map_copy(converterConfig.channelMapIn, pDevice->playback.channelMap, pDevice->playback.channels); ma_channel_map_copy(converterConfig.channelMapIn, pDevice->playback.channelMap, ma_min(pDevice->playback.channels, MA_MAX_CHANNELS));
converterConfig.formatOut = pDevice->playback.internalFormat; converterConfig.formatOut = pDevice->playback.internalFormat;
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, pDevice->playback.internalChannels); ma_channel_map_copy(converterConfig.channelMapOut, pDevice->playback.internalChannelMap, ma_min(pDevice->playback.internalChannels, MA_MAX_CHANNELS));
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;
...@@ -31219,7 +31246,8 @@ MA_API ma_result ma_device_init(ma_context* pContext, const ma_device_config* pC ...@@ -31219,7 +31246,8 @@ MA_API ma_result ma_device_init(ma_context* pContext, const ma_device_config* pC
pDevice->usingDefaultBufferSize = MA_TRUE; pDevice->usingDefaultBufferSize = MA_TRUE;
} }
MA_ASSERT(config.capture.channels <= MA_MAX_CHANNELS);
MA_ASSERT(config.playback.channels <= MA_MAX_CHANNELS);
pDevice->type = config.deviceType; pDevice->type = config.deviceType;
pDevice->sampleRate = config.sampleRate; pDevice->sampleRate = config.sampleRate;
...@@ -34315,6 +34343,10 @@ MA_API ma_result ma_biquad_init(const ma_biquad_config* pConfig, ma_biquad* pBQ) ...@@ -34315,6 +34343,10 @@ MA_API ma_result ma_biquad_init(const ma_biquad_config* pConfig, ma_biquad* pBQ)
return MA_INVALID_ARGS; return MA_INVALID_ARGS;
} }
if (pConfig->channels < MA_MIN_CHANNELS || pConfig->channels > MA_MAX_CHANNELS) {
return MA_INVALID_ARGS;
}
return ma_biquad_reinit(pConfig, pBQ); return ma_biquad_reinit(pConfig, pBQ);
} }
...@@ -34522,6 +34554,10 @@ MA_API ma_result ma_lpf1_init(const ma_lpf1_config* pConfig, ma_lpf1* pLPF) ...@@ -34522,6 +34554,10 @@ MA_API ma_result ma_lpf1_init(const ma_lpf1_config* pConfig, ma_lpf1* pLPF)
return MA_INVALID_ARGS; return MA_INVALID_ARGS;
} }
if (pConfig->channels < MA_MIN_CHANNELS || pConfig->channels > MA_MAX_CHANNELS) {
return MA_INVALID_ARGS;
}
return ma_lpf1_reinit(pConfig, pLPF); return ma_lpf1_reinit(pConfig, pLPF);
} }
...@@ -35024,6 +35060,10 @@ MA_API ma_result ma_hpf1_init(const ma_hpf1_config* pConfig, ma_hpf1* pHPF) ...@@ -35024,6 +35060,10 @@ MA_API ma_result ma_hpf1_init(const ma_hpf1_config* pConfig, ma_hpf1* pHPF)
return MA_INVALID_ARGS; return MA_INVALID_ARGS;
} }
if (pConfig->channels < MA_MIN_CHANNELS || pConfig->channels > MA_MAX_CHANNELS) {
return MA_INVALID_ARGS;
}
return ma_hpf1_reinit(pConfig, pHPF); return ma_hpf1_reinit(pConfig, pHPF);
} }
...@@ -36379,6 +36419,10 @@ MA_API ma_result ma_linear_resampler_init(const ma_linear_resampler_config* pCon ...@@ -36379,6 +36419,10 @@ MA_API ma_result ma_linear_resampler_init(const ma_linear_resampler_config* pCon
return MA_INVALID_ARGS; return MA_INVALID_ARGS;
} }
if (pConfig->channels < MA_MIN_CHANNELS || pConfig->channels > MA_MAX_CHANNELS) {
return MA_INVALID_ARGS;
}
pResampler->config = *pConfig; pResampler->config = *pConfig;
/* Setting the rate will set up the filter and time advances for us. */ /* Setting the rate will set up the filter and time advances for us. */
...@@ -37563,15 +37607,20 @@ static float ma_calculate_channel_position_rectangular_weight(ma_channel channel ...@@ -37563,15 +37607,20 @@ static float ma_calculate_channel_position_rectangular_weight(ma_channel channel
return contribution; return contribution;
} }
MA_API ma_channel_converter_config ma_channel_converter_config_init(ma_format format, ma_uint32 channelsIn, const ma_channel channelMapIn[MA_MAX_CHANNELS], ma_uint32 channelsOut, const ma_channel channelMapOut[MA_MAX_CHANNELS], ma_channel_mix_mode mixingMode) MA_API ma_channel_converter_config ma_channel_converter_config_init(ma_format format, ma_uint32 channelsIn, const ma_channel* pChannelMapIn, ma_uint32 channelsOut, const ma_channel* pChannelMapOut, ma_channel_mix_mode mixingMode)
{ {
ma_channel_converter_config config; ma_channel_converter_config config;
/* Channel counts need to be clamped. */
channelsIn = ma_min(channelsIn, ma_countof(config.channelMapIn));
channelsOut = ma_min(channelsOut, ma_countof(config.channelMapOut));
MA_ZERO_OBJECT(&config); MA_ZERO_OBJECT(&config);
config.format = format; config.format = format;
config.channelsIn = channelsIn; config.channelsIn = channelsIn;
config.channelsOut = channelsOut; config.channelsOut = channelsOut;
ma_channel_map_copy(config.channelMapIn, channelMapIn, channelsIn); ma_channel_map_copy(config.channelMapIn, pChannelMapIn, channelsIn);
ma_channel_map_copy(config.channelMapOut, channelMapOut, channelsOut); ma_channel_map_copy(config.channelMapOut, pChannelMapOut, channelsOut);
config.mixingMode = mixingMode; config.mixingMode = mixingMode;
return config; return config;
...@@ -37614,6 +37663,12 @@ MA_API ma_result ma_channel_converter_init(const ma_channel_converter_config* pC ...@@ -37614,6 +37663,12 @@ MA_API ma_result ma_channel_converter_init(const ma_channel_converter_config* pC
return MA_INVALID_ARGS; return MA_INVALID_ARGS;
} }
/* Basic validation for channel counts. */
if (pConfig->channelsIn < MA_MIN_CHANNELS || pConfig->channelsIn > MA_MAX_CHANNELS ||
pConfig->channelsOut < MA_MIN_CHANNELS || pConfig->channelsOut > MA_MAX_CHANNELS) {
return MA_INVALID_ARGS;
}
if (!ma_channel_map_valid(pConfig->channelsIn, pConfig->channelMapIn)) { if (!ma_channel_map_valid(pConfig->channelsIn, pConfig->channelMapIn)) {
return MA_INVALID_ARGS; /* Invalid input channel map. */ return MA_INVALID_ARGS; /* Invalid input channel map. */
} }
...@@ -38331,11 +38386,11 @@ MA_API ma_data_converter_config ma_data_converter_config_init_default() ...@@ -38331,11 +38386,11 @@ MA_API ma_data_converter_config ma_data_converter_config_init_default()
MA_API ma_data_converter_config ma_data_converter_config_init(ma_format formatIn, ma_format formatOut, ma_uint32 channelsIn, ma_uint32 channelsOut, ma_uint32 sampleRateIn, ma_uint32 sampleRateOut) MA_API ma_data_converter_config ma_data_converter_config_init(ma_format formatIn, ma_format formatOut, ma_uint32 channelsIn, ma_uint32 channelsOut, ma_uint32 sampleRateIn, ma_uint32 sampleRateOut)
{ {
ma_data_converter_config config = ma_data_converter_config_init_default(); ma_data_converter_config config = ma_data_converter_config_init_default();
config.formatIn = formatIn; config.formatIn = formatIn;
config.formatOut = formatOut; config.formatOut = formatOut;
config.channelsIn = channelsIn; config.channelsIn = ma_min(channelsIn, MA_MAX_CHANNELS);
config.channelsOut = channelsOut; config.channelsOut = ma_min(channelsOut, MA_MAX_CHANNELS);
config.sampleRateIn = sampleRateIn; config.sampleRateIn = sampleRateIn;
config.sampleRateOut = sampleRateOut; config.sampleRateOut = sampleRateOut;
return config; return config;
...@@ -39235,479 +39290,499 @@ MA_API ma_uint64 ma_data_converter_get_output_latency(ma_data_converter* pConver ...@@ -39235,479 +39290,499 @@ MA_API ma_uint64 ma_data_converter_get_output_latency(ma_data_converter* pConver
Channel Maps Channel Maps
**************************************************************************************************************************************************************/ **************************************************************************************************************************************************************/
static void ma_get_standard_channel_map_microsoft(ma_uint32 channels, ma_channel channelMap[MA_MAX_CHANNELS]) 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 */
switch (channels) switch (channels)
{ {
case 1: case 1:
{ {
channelMap[0] = MA_CHANNEL_MONO; pChannelMap[0] = MA_CHANNEL_MONO;
} break; } break;
case 2: case 2:
{ {
channelMap[0] = MA_CHANNEL_FRONT_LEFT; pChannelMap[0] = MA_CHANNEL_FRONT_LEFT;
channelMap[1] = MA_CHANNEL_FRONT_RIGHT; pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT;
} break; } break;
case 3: /* Not defined, but best guess. */ case 3: /* Not defined, but best guess. */
{ {
channelMap[0] = MA_CHANNEL_FRONT_LEFT; pChannelMap[0] = MA_CHANNEL_FRONT_LEFT;
channelMap[1] = MA_CHANNEL_FRONT_RIGHT; pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT;
channelMap[2] = MA_CHANNEL_FRONT_CENTER; pChannelMap[2] = MA_CHANNEL_FRONT_CENTER;
} break; } break;
case 4: case 4:
{ {
#ifndef MA_USE_QUAD_MICROSOFT_CHANNEL_MAP #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. */ /* 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; pChannelMap[0] = MA_CHANNEL_FRONT_LEFT;
channelMap[1] = MA_CHANNEL_FRONT_RIGHT; pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT;
channelMap[2] = MA_CHANNEL_FRONT_CENTER; pChannelMap[2] = MA_CHANNEL_FRONT_CENTER;
channelMap[3] = MA_CHANNEL_BACK_CENTER; pChannelMap[3] = MA_CHANNEL_BACK_CENTER;
#else #else
/* Quad. */ /* Quad. */
channelMap[0] = MA_CHANNEL_FRONT_LEFT; pChannelMap[0] = MA_CHANNEL_FRONT_LEFT;
channelMap[1] = MA_CHANNEL_FRONT_RIGHT; pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT;
channelMap[2] = MA_CHANNEL_BACK_LEFT; pChannelMap[2] = MA_CHANNEL_BACK_LEFT;
channelMap[3] = MA_CHANNEL_BACK_RIGHT; pChannelMap[3] = MA_CHANNEL_BACK_RIGHT;
#endif #endif
} break; } break;
case 5: /* Not defined, but best guess. */ case 5: /* Not defined, but best guess. */
{ {
channelMap[0] = MA_CHANNEL_FRONT_LEFT; pChannelMap[0] = MA_CHANNEL_FRONT_LEFT;
channelMap[1] = MA_CHANNEL_FRONT_RIGHT; pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT;
channelMap[2] = MA_CHANNEL_FRONT_CENTER; pChannelMap[2] = MA_CHANNEL_FRONT_CENTER;
channelMap[3] = MA_CHANNEL_BACK_LEFT; pChannelMap[3] = MA_CHANNEL_BACK_LEFT;
channelMap[4] = MA_CHANNEL_BACK_RIGHT; pChannelMap[4] = MA_CHANNEL_BACK_RIGHT;
} break; } break;
case 6: case 6:
{ {
channelMap[0] = MA_CHANNEL_FRONT_LEFT; pChannelMap[0] = MA_CHANNEL_FRONT_LEFT;
channelMap[1] = MA_CHANNEL_FRONT_RIGHT; pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT;
channelMap[2] = MA_CHANNEL_FRONT_CENTER; pChannelMap[2] = MA_CHANNEL_FRONT_CENTER;
channelMap[3] = MA_CHANNEL_LFE; pChannelMap[3] = MA_CHANNEL_LFE;
channelMap[4] = MA_CHANNEL_SIDE_LEFT; pChannelMap[4] = MA_CHANNEL_SIDE_LEFT;
channelMap[5] = MA_CHANNEL_SIDE_RIGHT; pChannelMap[5] = MA_CHANNEL_SIDE_RIGHT;
} break; } break;
case 7: /* Not defined, but best guess. */ case 7: /* Not defined, but best guess. */
{ {
channelMap[0] = MA_CHANNEL_FRONT_LEFT; pChannelMap[0] = MA_CHANNEL_FRONT_LEFT;
channelMap[1] = MA_CHANNEL_FRONT_RIGHT; pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT;
channelMap[2] = MA_CHANNEL_FRONT_CENTER; pChannelMap[2] = MA_CHANNEL_FRONT_CENTER;
channelMap[3] = MA_CHANNEL_LFE; pChannelMap[3] = MA_CHANNEL_LFE;
channelMap[4] = MA_CHANNEL_BACK_CENTER; pChannelMap[4] = MA_CHANNEL_BACK_CENTER;
channelMap[5] = MA_CHANNEL_SIDE_LEFT; pChannelMap[5] = MA_CHANNEL_SIDE_LEFT;
channelMap[6] = MA_CHANNEL_SIDE_RIGHT; pChannelMap[6] = MA_CHANNEL_SIDE_RIGHT;
} break; } break;
case 8: case 8:
default: default:
{ {
channelMap[0] = MA_CHANNEL_FRONT_LEFT; pChannelMap[0] = MA_CHANNEL_FRONT_LEFT;
channelMap[1] = MA_CHANNEL_FRONT_RIGHT; pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT;
channelMap[2] = MA_CHANNEL_FRONT_CENTER; pChannelMap[2] = MA_CHANNEL_FRONT_CENTER;
channelMap[3] = MA_CHANNEL_LFE; pChannelMap[3] = MA_CHANNEL_LFE;
channelMap[4] = MA_CHANNEL_BACK_LEFT; pChannelMap[4] = MA_CHANNEL_BACK_LEFT;
channelMap[5] = MA_CHANNEL_BACK_RIGHT; pChannelMap[5] = MA_CHANNEL_BACK_RIGHT;
channelMap[6] = MA_CHANNEL_SIDE_LEFT; pChannelMap[6] = MA_CHANNEL_SIDE_LEFT;
channelMap[7] = MA_CHANNEL_SIDE_RIGHT; pChannelMap[7] = MA_CHANNEL_SIDE_RIGHT;
} break; } break;
} }
/* Remainder. */ /* Remainder. */
if (channels > 8) { if (channels > 8) {
ma_uint32 iChannel; ma_uint32 iChannel;
for (iChannel = 8; iChannel < MA_MAX_CHANNELS; ++iChannel) { for (iChannel = 8; iChannel < channels; ++iChannel) {
channelMap[iChannel] = (ma_channel)(MA_CHANNEL_AUX_0 + (iChannel-8)); if (iChannel < MA_MAX_CHANNELS) {
pChannelMap[iChannel] = (ma_channel)(MA_CHANNEL_AUX_0 + (iChannel-8));
} else {
pChannelMap[iChannel] = MA_CHANNEL_NONE;
}
} }
} }
} }
static void ma_get_standard_channel_map_alsa(ma_uint32 channels, ma_channel channelMap[MA_MAX_CHANNELS]) static void ma_get_standard_channel_map_alsa(ma_uint32 channels, ma_channel* pChannelMap)
{ {
switch (channels) switch (channels)
{ {
case 1: case 1:
{ {
channelMap[0] = MA_CHANNEL_MONO; pChannelMap[0] = MA_CHANNEL_MONO;
} break; } break;
case 2: case 2:
{ {
channelMap[0] = MA_CHANNEL_LEFT; pChannelMap[0] = MA_CHANNEL_LEFT;
channelMap[1] = MA_CHANNEL_RIGHT; pChannelMap[1] = MA_CHANNEL_RIGHT;
} break; } break;
case 3: case 3:
{ {
channelMap[0] = MA_CHANNEL_FRONT_LEFT; pChannelMap[0] = MA_CHANNEL_FRONT_LEFT;
channelMap[1] = MA_CHANNEL_FRONT_RIGHT; pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT;
channelMap[2] = MA_CHANNEL_FRONT_CENTER; pChannelMap[2] = MA_CHANNEL_FRONT_CENTER;
} break; } break;
case 4: case 4:
{ {
channelMap[0] = MA_CHANNEL_FRONT_LEFT; pChannelMap[0] = MA_CHANNEL_FRONT_LEFT;
channelMap[1] = MA_CHANNEL_FRONT_RIGHT; pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT;
channelMap[2] = MA_CHANNEL_BACK_LEFT; pChannelMap[2] = MA_CHANNEL_BACK_LEFT;
channelMap[3] = MA_CHANNEL_BACK_RIGHT; pChannelMap[3] = MA_CHANNEL_BACK_RIGHT;
} break; } break;
case 5: case 5:
{ {
channelMap[0] = MA_CHANNEL_FRONT_LEFT; pChannelMap[0] = MA_CHANNEL_FRONT_LEFT;
channelMap[1] = MA_CHANNEL_FRONT_RIGHT; pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT;
channelMap[2] = MA_CHANNEL_BACK_LEFT; pChannelMap[2] = MA_CHANNEL_BACK_LEFT;
channelMap[3] = MA_CHANNEL_BACK_RIGHT; pChannelMap[3] = MA_CHANNEL_BACK_RIGHT;
channelMap[4] = MA_CHANNEL_FRONT_CENTER; pChannelMap[4] = MA_CHANNEL_FRONT_CENTER;
} break; } break;
case 6: case 6:
{ {
channelMap[0] = MA_CHANNEL_FRONT_LEFT; pChannelMap[0] = MA_CHANNEL_FRONT_LEFT;
channelMap[1] = MA_CHANNEL_FRONT_RIGHT; pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT;
channelMap[2] = MA_CHANNEL_BACK_LEFT; pChannelMap[2] = MA_CHANNEL_BACK_LEFT;
channelMap[3] = MA_CHANNEL_BACK_RIGHT; pChannelMap[3] = MA_CHANNEL_BACK_RIGHT;
channelMap[4] = MA_CHANNEL_FRONT_CENTER; pChannelMap[4] = MA_CHANNEL_FRONT_CENTER;
channelMap[5] = MA_CHANNEL_LFE; pChannelMap[5] = MA_CHANNEL_LFE;
} break; } break;
case 7: case 7:
{ {
channelMap[0] = MA_CHANNEL_FRONT_LEFT; pChannelMap[0] = MA_CHANNEL_FRONT_LEFT;
channelMap[1] = MA_CHANNEL_FRONT_RIGHT; pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT;
channelMap[2] = MA_CHANNEL_BACK_LEFT; pChannelMap[2] = MA_CHANNEL_BACK_LEFT;
channelMap[3] = MA_CHANNEL_BACK_RIGHT; pChannelMap[3] = MA_CHANNEL_BACK_RIGHT;
channelMap[4] = MA_CHANNEL_FRONT_CENTER; pChannelMap[4] = MA_CHANNEL_FRONT_CENTER;
channelMap[5] = MA_CHANNEL_LFE; pChannelMap[5] = MA_CHANNEL_LFE;
channelMap[6] = MA_CHANNEL_BACK_CENTER; pChannelMap[6] = MA_CHANNEL_BACK_CENTER;
} break; } break;
case 8: case 8:
default: default:
{ {
channelMap[0] = MA_CHANNEL_FRONT_LEFT; pChannelMap[0] = MA_CHANNEL_FRONT_LEFT;
channelMap[1] = MA_CHANNEL_FRONT_RIGHT; pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT;
channelMap[2] = MA_CHANNEL_BACK_LEFT; pChannelMap[2] = MA_CHANNEL_BACK_LEFT;
channelMap[3] = MA_CHANNEL_BACK_RIGHT; pChannelMap[3] = MA_CHANNEL_BACK_RIGHT;
channelMap[4] = MA_CHANNEL_FRONT_CENTER; pChannelMap[4] = MA_CHANNEL_FRONT_CENTER;
channelMap[5] = MA_CHANNEL_LFE; pChannelMap[5] = MA_CHANNEL_LFE;
channelMap[6] = MA_CHANNEL_SIDE_LEFT; pChannelMap[6] = MA_CHANNEL_SIDE_LEFT;
channelMap[7] = MA_CHANNEL_SIDE_RIGHT; pChannelMap[7] = MA_CHANNEL_SIDE_RIGHT;
} break; } break;
} }
/* Remainder. */ /* Remainder. */
if (channels > 8) { if (channels > 8) {
ma_uint32 iChannel; ma_uint32 iChannel;
for (iChannel = 8; iChannel < MA_MAX_CHANNELS; ++iChannel) { for (iChannel = 8; iChannel < channels; ++iChannel) {
channelMap[iChannel] = (ma_channel)(MA_CHANNEL_AUX_0 + (iChannel-8)); if (iChannel < MA_MAX_CHANNELS) {
pChannelMap[iChannel] = (ma_channel)(MA_CHANNEL_AUX_0 + (iChannel-8));
} else {
pChannelMap[iChannel] = MA_CHANNEL_NONE;
}
} }
} }
} }
static void ma_get_standard_channel_map_rfc3551(ma_uint32 channels, ma_channel channelMap[MA_MAX_CHANNELS]) static void ma_get_standard_channel_map_rfc3551(ma_uint32 channels, ma_channel* pChannelMap)
{ {
switch (channels) switch (channels)
{ {
case 1: case 1:
{ {
channelMap[0] = MA_CHANNEL_MONO; pChannelMap[0] = MA_CHANNEL_MONO;
} break; } break;
case 2: case 2:
{ {
channelMap[0] = MA_CHANNEL_LEFT; pChannelMap[0] = MA_CHANNEL_LEFT;
channelMap[1] = MA_CHANNEL_RIGHT; pChannelMap[1] = MA_CHANNEL_RIGHT;
} break; } break;
case 3: case 3:
{ {
channelMap[0] = MA_CHANNEL_FRONT_LEFT; pChannelMap[0] = MA_CHANNEL_FRONT_LEFT;
channelMap[1] = MA_CHANNEL_FRONT_RIGHT; pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT;
channelMap[2] = MA_CHANNEL_FRONT_CENTER; pChannelMap[2] = MA_CHANNEL_FRONT_CENTER;
} break; } break;
case 4: case 4:
{ {
channelMap[0] = MA_CHANNEL_FRONT_LEFT; pChannelMap[0] = MA_CHANNEL_FRONT_LEFT;
channelMap[1] = MA_CHANNEL_FRONT_CENTER; pChannelMap[1] = MA_CHANNEL_FRONT_CENTER;
channelMap[2] = MA_CHANNEL_FRONT_RIGHT; pChannelMap[2] = MA_CHANNEL_FRONT_RIGHT;
channelMap[3] = MA_CHANNEL_BACK_CENTER; pChannelMap[3] = MA_CHANNEL_BACK_CENTER;
} break; } break;
case 5: case 5:
{ {
channelMap[0] = MA_CHANNEL_FRONT_LEFT; pChannelMap[0] = MA_CHANNEL_FRONT_LEFT;
channelMap[1] = MA_CHANNEL_FRONT_RIGHT; pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT;
channelMap[2] = MA_CHANNEL_FRONT_CENTER; pChannelMap[2] = MA_CHANNEL_FRONT_CENTER;
channelMap[3] = MA_CHANNEL_BACK_LEFT; pChannelMap[3] = MA_CHANNEL_BACK_LEFT;
channelMap[4] = MA_CHANNEL_BACK_RIGHT; pChannelMap[4] = MA_CHANNEL_BACK_RIGHT;
} break; } break;
case 6: case 6:
{ {
channelMap[0] = MA_CHANNEL_FRONT_LEFT; pChannelMap[0] = MA_CHANNEL_FRONT_LEFT;
channelMap[1] = MA_CHANNEL_SIDE_LEFT; pChannelMap[1] = MA_CHANNEL_SIDE_LEFT;
channelMap[2] = MA_CHANNEL_FRONT_CENTER; pChannelMap[2] = MA_CHANNEL_FRONT_CENTER;
channelMap[3] = MA_CHANNEL_FRONT_RIGHT; pChannelMap[3] = MA_CHANNEL_FRONT_RIGHT;
channelMap[4] = MA_CHANNEL_SIDE_RIGHT; pChannelMap[4] = MA_CHANNEL_SIDE_RIGHT;
channelMap[5] = MA_CHANNEL_BACK_CENTER; pChannelMap[5] = MA_CHANNEL_BACK_CENTER;
} break; } break;
} }
/* Remainder. */ /* Remainder. */
if (channels > 8) { if (channels > 8) {
ma_uint32 iChannel; ma_uint32 iChannel;
for (iChannel = 6; iChannel < MA_MAX_CHANNELS; ++iChannel) { for (iChannel = 6; iChannel < channels; ++iChannel) {
channelMap[iChannel] = (ma_channel)(MA_CHANNEL_AUX_0 + (iChannel-6)); if (iChannel < MA_MAX_CHANNELS) {
pChannelMap[iChannel] = (ma_channel)(MA_CHANNEL_AUX_0 + (iChannel-6));
} else {
pChannelMap[iChannel] = MA_CHANNEL_NONE;
}
} }
} }
} }
static void ma_get_standard_channel_map_flac(ma_uint32 channels, ma_channel channelMap[MA_MAX_CHANNELS]) static void ma_get_standard_channel_map_flac(ma_uint32 channels, ma_channel* pChannelMap)
{ {
switch (channels) switch (channels)
{ {
case 1: case 1:
{ {
channelMap[0] = MA_CHANNEL_MONO; pChannelMap[0] = MA_CHANNEL_MONO;
} break; } break;
case 2: case 2:
{ {
channelMap[0] = MA_CHANNEL_LEFT; pChannelMap[0] = MA_CHANNEL_LEFT;
channelMap[1] = MA_CHANNEL_RIGHT; pChannelMap[1] = MA_CHANNEL_RIGHT;
} break; } break;
case 3: case 3:
{ {
channelMap[0] = MA_CHANNEL_FRONT_LEFT; pChannelMap[0] = MA_CHANNEL_FRONT_LEFT;
channelMap[1] = MA_CHANNEL_FRONT_RIGHT; pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT;
channelMap[2] = MA_CHANNEL_FRONT_CENTER; pChannelMap[2] = MA_CHANNEL_FRONT_CENTER;
} break; } break;
case 4: case 4:
{ {
channelMap[0] = MA_CHANNEL_FRONT_LEFT; pChannelMap[0] = MA_CHANNEL_FRONT_LEFT;
channelMap[1] = MA_CHANNEL_FRONT_RIGHT; pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT;
channelMap[2] = MA_CHANNEL_BACK_LEFT; pChannelMap[2] = MA_CHANNEL_BACK_LEFT;
channelMap[3] = MA_CHANNEL_BACK_RIGHT; pChannelMap[3] = MA_CHANNEL_BACK_RIGHT;
} break; } break;
case 5: case 5:
{ {
channelMap[0] = MA_CHANNEL_FRONT_LEFT; pChannelMap[0] = MA_CHANNEL_FRONT_LEFT;
channelMap[1] = MA_CHANNEL_FRONT_RIGHT; pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT;
channelMap[2] = MA_CHANNEL_FRONT_CENTER; pChannelMap[2] = MA_CHANNEL_FRONT_CENTER;
channelMap[3] = MA_CHANNEL_BACK_LEFT; pChannelMap[3] = MA_CHANNEL_BACK_LEFT;
channelMap[4] = MA_CHANNEL_BACK_RIGHT; pChannelMap[4] = MA_CHANNEL_BACK_RIGHT;
} break; } break;
case 6: case 6:
{ {
channelMap[0] = MA_CHANNEL_FRONT_LEFT; pChannelMap[0] = MA_CHANNEL_FRONT_LEFT;
channelMap[1] = MA_CHANNEL_FRONT_RIGHT; pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT;
channelMap[2] = MA_CHANNEL_FRONT_CENTER; pChannelMap[2] = MA_CHANNEL_FRONT_CENTER;
channelMap[3] = MA_CHANNEL_LFE; pChannelMap[3] = MA_CHANNEL_LFE;
channelMap[4] = MA_CHANNEL_BACK_LEFT; pChannelMap[4] = MA_CHANNEL_BACK_LEFT;
channelMap[5] = MA_CHANNEL_BACK_RIGHT; pChannelMap[5] = MA_CHANNEL_BACK_RIGHT;
} break; } break;
case 7: case 7:
{ {
channelMap[0] = MA_CHANNEL_FRONT_LEFT; pChannelMap[0] = MA_CHANNEL_FRONT_LEFT;
channelMap[1] = MA_CHANNEL_FRONT_RIGHT; pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT;
channelMap[2] = MA_CHANNEL_FRONT_CENTER; pChannelMap[2] = MA_CHANNEL_FRONT_CENTER;
channelMap[3] = MA_CHANNEL_LFE; pChannelMap[3] = MA_CHANNEL_LFE;
channelMap[4] = MA_CHANNEL_BACK_CENTER; pChannelMap[4] = MA_CHANNEL_BACK_CENTER;
channelMap[5] = MA_CHANNEL_SIDE_LEFT; pChannelMap[5] = MA_CHANNEL_SIDE_LEFT;
channelMap[6] = MA_CHANNEL_SIDE_RIGHT; pChannelMap[6] = MA_CHANNEL_SIDE_RIGHT;
} break; } break;
case 8: case 8:
default: default:
{ {
channelMap[0] = MA_CHANNEL_FRONT_LEFT; pChannelMap[0] = MA_CHANNEL_FRONT_LEFT;
channelMap[1] = MA_CHANNEL_FRONT_RIGHT; pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT;
channelMap[2] = MA_CHANNEL_FRONT_CENTER; pChannelMap[2] = MA_CHANNEL_FRONT_CENTER;
channelMap[3] = MA_CHANNEL_LFE; pChannelMap[3] = MA_CHANNEL_LFE;
channelMap[4] = MA_CHANNEL_BACK_LEFT; pChannelMap[4] = MA_CHANNEL_BACK_LEFT;
channelMap[5] = MA_CHANNEL_BACK_RIGHT; pChannelMap[5] = MA_CHANNEL_BACK_RIGHT;
channelMap[6] = MA_CHANNEL_SIDE_LEFT; pChannelMap[6] = MA_CHANNEL_SIDE_LEFT;
channelMap[7] = MA_CHANNEL_SIDE_RIGHT; pChannelMap[7] = MA_CHANNEL_SIDE_RIGHT;
} break; } break;
} }
/* Remainder. */ /* Remainder. */
if (channels > 8) { if (channels > 8) {
ma_uint32 iChannel; ma_uint32 iChannel;
for (iChannel = 8; iChannel < MA_MAX_CHANNELS; ++iChannel) { for (iChannel = 8; iChannel < channels; ++iChannel) {
channelMap[iChannel] = (ma_channel)(MA_CHANNEL_AUX_0 + (iChannel-8)); if (iChannel < MA_MAX_CHANNELS) {
pChannelMap[iChannel] = (ma_channel)(MA_CHANNEL_AUX_0 + (iChannel-8));
} else {
pChannelMap[iChannel] = MA_CHANNEL_NONE;
}
} }
} }
} }
static void ma_get_standard_channel_map_vorbis(ma_uint32 channels, ma_channel channelMap[MA_MAX_CHANNELS]) static void ma_get_standard_channel_map_vorbis(ma_uint32 channels, ma_channel* pChannelMap)
{ {
/* 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?! */ /* 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) switch (channels)
{ {
case 1: case 1:
{ {
channelMap[0] = MA_CHANNEL_MONO; pChannelMap[0] = MA_CHANNEL_MONO;
} break; } break;
case 2: case 2:
{ {
channelMap[0] = MA_CHANNEL_LEFT; pChannelMap[0] = MA_CHANNEL_LEFT;
channelMap[1] = MA_CHANNEL_RIGHT; pChannelMap[1] = MA_CHANNEL_RIGHT;
} break; } break;
case 3: case 3:
{ {
channelMap[0] = MA_CHANNEL_FRONT_LEFT; pChannelMap[0] = MA_CHANNEL_FRONT_LEFT;
channelMap[1] = MA_CHANNEL_FRONT_CENTER; pChannelMap[1] = MA_CHANNEL_FRONT_CENTER;
channelMap[2] = MA_CHANNEL_FRONT_RIGHT; pChannelMap[2] = MA_CHANNEL_FRONT_RIGHT;
} break; } break;
case 4: case 4:
{ {
channelMap[0] = MA_CHANNEL_FRONT_LEFT; pChannelMap[0] = MA_CHANNEL_FRONT_LEFT;
channelMap[1] = MA_CHANNEL_FRONT_RIGHT; pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT;
channelMap[2] = MA_CHANNEL_BACK_LEFT; pChannelMap[2] = MA_CHANNEL_BACK_LEFT;
channelMap[3] = MA_CHANNEL_BACK_RIGHT; pChannelMap[3] = MA_CHANNEL_BACK_RIGHT;
} break; } break;
case 5: case 5:
{ {
channelMap[0] = MA_CHANNEL_FRONT_LEFT; pChannelMap[0] = MA_CHANNEL_FRONT_LEFT;
channelMap[1] = MA_CHANNEL_FRONT_CENTER; pChannelMap[1] = MA_CHANNEL_FRONT_CENTER;
channelMap[2] = MA_CHANNEL_FRONT_RIGHT; pChannelMap[2] = MA_CHANNEL_FRONT_RIGHT;
channelMap[3] = MA_CHANNEL_BACK_LEFT; pChannelMap[3] = MA_CHANNEL_BACK_LEFT;
channelMap[4] = MA_CHANNEL_BACK_RIGHT; pChannelMap[4] = MA_CHANNEL_BACK_RIGHT;
} break; } break;
case 6: case 6:
{ {
channelMap[0] = MA_CHANNEL_FRONT_LEFT; pChannelMap[0] = MA_CHANNEL_FRONT_LEFT;
channelMap[1] = MA_CHANNEL_FRONT_CENTER; pChannelMap[1] = MA_CHANNEL_FRONT_CENTER;
channelMap[2] = MA_CHANNEL_FRONT_RIGHT; pChannelMap[2] = MA_CHANNEL_FRONT_RIGHT;
channelMap[3] = MA_CHANNEL_BACK_LEFT; pChannelMap[3] = MA_CHANNEL_BACK_LEFT;
channelMap[4] = MA_CHANNEL_BACK_RIGHT; pChannelMap[4] = MA_CHANNEL_BACK_RIGHT;
channelMap[5] = MA_CHANNEL_LFE; pChannelMap[5] = MA_CHANNEL_LFE;
} break; } break;
case 7: case 7:
{ {
channelMap[0] = MA_CHANNEL_FRONT_LEFT; pChannelMap[0] = MA_CHANNEL_FRONT_LEFT;
channelMap[1] = MA_CHANNEL_FRONT_CENTER; pChannelMap[1] = MA_CHANNEL_FRONT_CENTER;
channelMap[2] = MA_CHANNEL_FRONT_RIGHT; pChannelMap[2] = MA_CHANNEL_FRONT_RIGHT;
channelMap[3] = MA_CHANNEL_SIDE_LEFT; pChannelMap[3] = MA_CHANNEL_SIDE_LEFT;
channelMap[4] = MA_CHANNEL_SIDE_RIGHT; pChannelMap[4] = MA_CHANNEL_SIDE_RIGHT;
channelMap[5] = MA_CHANNEL_BACK_CENTER; pChannelMap[5] = MA_CHANNEL_BACK_CENTER;
channelMap[6] = MA_CHANNEL_LFE; pChannelMap[6] = MA_CHANNEL_LFE;
} break; } break;
case 8: case 8:
default: default:
{ {
channelMap[0] = MA_CHANNEL_FRONT_LEFT; pChannelMap[0] = MA_CHANNEL_FRONT_LEFT;
channelMap[1] = MA_CHANNEL_FRONT_CENTER; pChannelMap[1] = MA_CHANNEL_FRONT_CENTER;
channelMap[2] = MA_CHANNEL_FRONT_RIGHT; pChannelMap[2] = MA_CHANNEL_FRONT_RIGHT;
channelMap[3] = MA_CHANNEL_SIDE_LEFT; pChannelMap[3] = MA_CHANNEL_SIDE_LEFT;
channelMap[4] = MA_CHANNEL_SIDE_RIGHT; pChannelMap[4] = MA_CHANNEL_SIDE_RIGHT;
channelMap[5] = MA_CHANNEL_BACK_LEFT; pChannelMap[5] = MA_CHANNEL_BACK_LEFT;
channelMap[6] = MA_CHANNEL_BACK_RIGHT; pChannelMap[6] = MA_CHANNEL_BACK_RIGHT;
channelMap[7] = MA_CHANNEL_LFE; pChannelMap[7] = MA_CHANNEL_LFE;
} break; } break;
} }
/* Remainder. */ /* Remainder. */
if (channels > 8) { if (channels > 8) {
ma_uint32 iChannel; ma_uint32 iChannel;
for (iChannel = 8; iChannel < MA_MAX_CHANNELS; ++iChannel) { for (iChannel = 8; iChannel < channels; ++iChannel) {
channelMap[iChannel] = (ma_channel)(MA_CHANNEL_AUX_0 + (iChannel-8)); if (iChannel < MA_MAX_CHANNELS) {
pChannelMap[iChannel] = (ma_channel)(MA_CHANNEL_AUX_0 + (iChannel-8));
} else {
pChannelMap[iChannel] = MA_CHANNEL_NONE;
}
} }
} }
} }
static void ma_get_standard_channel_map_sound4(ma_uint32 channels, ma_channel channelMap[MA_MAX_CHANNELS]) static void ma_get_standard_channel_map_sound4(ma_uint32 channels, ma_channel* pChannelMap)
{ {
switch (channels) switch (channels)
{ {
case 1: case 1:
{ {
channelMap[0] = MA_CHANNEL_MONO; pChannelMap[0] = MA_CHANNEL_MONO;
} break; } break;
case 2: case 2:
{ {
channelMap[0] = MA_CHANNEL_LEFT; pChannelMap[0] = MA_CHANNEL_LEFT;
channelMap[1] = MA_CHANNEL_RIGHT; pChannelMap[1] = MA_CHANNEL_RIGHT;
} break; } break;
case 3: case 3:
{ {
channelMap[0] = MA_CHANNEL_FRONT_LEFT; pChannelMap[0] = MA_CHANNEL_FRONT_LEFT;
channelMap[1] = MA_CHANNEL_FRONT_RIGHT; pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT;
channelMap[2] = MA_CHANNEL_BACK_CENTER; pChannelMap[2] = MA_CHANNEL_BACK_CENTER;
} break; } break;
case 4: case 4:
{ {
channelMap[0] = MA_CHANNEL_FRONT_LEFT; pChannelMap[0] = MA_CHANNEL_FRONT_LEFT;
channelMap[1] = MA_CHANNEL_FRONT_RIGHT; pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT;
channelMap[2] = MA_CHANNEL_BACK_LEFT; pChannelMap[2] = MA_CHANNEL_BACK_LEFT;
channelMap[3] = MA_CHANNEL_BACK_RIGHT; pChannelMap[3] = MA_CHANNEL_BACK_RIGHT;
} break; } break;
case 5: case 5:
{ {
channelMap[0] = MA_CHANNEL_FRONT_LEFT; pChannelMap[0] = MA_CHANNEL_FRONT_LEFT;
channelMap[1] = MA_CHANNEL_FRONT_RIGHT; pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT;
channelMap[2] = MA_CHANNEL_BACK_LEFT; pChannelMap[2] = MA_CHANNEL_BACK_LEFT;
channelMap[3] = MA_CHANNEL_BACK_RIGHT; pChannelMap[3] = MA_CHANNEL_BACK_RIGHT;
channelMap[4] = MA_CHANNEL_FRONT_CENTER; pChannelMap[4] = MA_CHANNEL_FRONT_CENTER;
} break; } break;
case 6: case 6:
{ {
channelMap[0] = MA_CHANNEL_FRONT_LEFT; pChannelMap[0] = MA_CHANNEL_FRONT_LEFT;
channelMap[1] = MA_CHANNEL_FRONT_RIGHT; pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT;
channelMap[2] = MA_CHANNEL_BACK_LEFT; pChannelMap[2] = MA_CHANNEL_BACK_LEFT;
channelMap[3] = MA_CHANNEL_BACK_RIGHT; pChannelMap[3] = MA_CHANNEL_BACK_RIGHT;
channelMap[4] = MA_CHANNEL_FRONT_CENTER; pChannelMap[4] = MA_CHANNEL_FRONT_CENTER;
channelMap[5] = MA_CHANNEL_LFE; pChannelMap[5] = MA_CHANNEL_LFE;
} break; } break;
case 7: case 7:
{ {
channelMap[0] = MA_CHANNEL_FRONT_LEFT; pChannelMap[0] = MA_CHANNEL_FRONT_LEFT;
channelMap[1] = MA_CHANNEL_FRONT_RIGHT; pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT;
channelMap[2] = MA_CHANNEL_BACK_LEFT; pChannelMap[2] = MA_CHANNEL_BACK_LEFT;
channelMap[3] = MA_CHANNEL_BACK_RIGHT; pChannelMap[3] = MA_CHANNEL_BACK_RIGHT;
channelMap[4] = MA_CHANNEL_FRONT_CENTER; pChannelMap[4] = MA_CHANNEL_FRONT_CENTER;
channelMap[5] = MA_CHANNEL_BACK_CENTER; pChannelMap[5] = MA_CHANNEL_BACK_CENTER;
channelMap[6] = MA_CHANNEL_LFE; pChannelMap[6] = MA_CHANNEL_LFE;
} break; } break;
case 8: case 8:
default: default:
{ {
channelMap[0] = MA_CHANNEL_FRONT_LEFT; pChannelMap[0] = MA_CHANNEL_FRONT_LEFT;
channelMap[1] = MA_CHANNEL_FRONT_RIGHT; pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT;
channelMap[2] = MA_CHANNEL_BACK_LEFT; pChannelMap[2] = MA_CHANNEL_BACK_LEFT;
channelMap[3] = MA_CHANNEL_BACK_RIGHT; pChannelMap[3] = MA_CHANNEL_BACK_RIGHT;
channelMap[4] = MA_CHANNEL_FRONT_CENTER; pChannelMap[4] = MA_CHANNEL_FRONT_CENTER;
channelMap[5] = MA_CHANNEL_LFE; pChannelMap[5] = MA_CHANNEL_LFE;
channelMap[6] = MA_CHANNEL_SIDE_LEFT; pChannelMap[6] = MA_CHANNEL_SIDE_LEFT;
channelMap[7] = MA_CHANNEL_SIDE_RIGHT; pChannelMap[7] = MA_CHANNEL_SIDE_RIGHT;
} break; } break;
} }
...@@ -39715,109 +39790,117 @@ static void ma_get_standard_channel_map_sound4(ma_uint32 channels, ma_channel ch ...@@ -39715,109 +39790,117 @@ static void ma_get_standard_channel_map_sound4(ma_uint32 channels, ma_channel ch
if (channels > 8) { if (channels > 8) {
ma_uint32 iChannel; ma_uint32 iChannel;
for (iChannel = 8; iChannel < MA_MAX_CHANNELS; ++iChannel) { for (iChannel = 8; iChannel < MA_MAX_CHANNELS; ++iChannel) {
channelMap[iChannel] = (ma_channel)(MA_CHANNEL_AUX_0 + (iChannel-8)); if (iChannel < MA_MAX_CHANNELS) {
pChannelMap[iChannel] = (ma_channel)(MA_CHANNEL_AUX_0 + (iChannel-8));
} else {
pChannelMap[iChannel] = MA_CHANNEL_NONE;
}
} }
} }
} }
static void ma_get_standard_channel_map_sndio(ma_uint32 channels, ma_channel channelMap[MA_MAX_CHANNELS]) static void ma_get_standard_channel_map_sndio(ma_uint32 channels, ma_channel* pChannelMap)
{ {
switch (channels) switch (channels)
{ {
case 1: case 1:
{ {
channelMap[0] = MA_CHANNEL_MONO; pChannelMap[0] = MA_CHANNEL_MONO;
} break; } break;
case 2: case 2:
{ {
channelMap[0] = MA_CHANNEL_LEFT; pChannelMap[0] = MA_CHANNEL_LEFT;
channelMap[1] = MA_CHANNEL_RIGHT; pChannelMap[1] = MA_CHANNEL_RIGHT;
} break; } break;
case 3: case 3:
{ {
channelMap[0] = MA_CHANNEL_FRONT_LEFT; pChannelMap[0] = MA_CHANNEL_FRONT_LEFT;
channelMap[1] = MA_CHANNEL_FRONT_RIGHT; pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT;
channelMap[2] = MA_CHANNEL_FRONT_CENTER; pChannelMap[2] = MA_CHANNEL_FRONT_CENTER;
} break; } break;
case 4: case 4:
{ {
channelMap[0] = MA_CHANNEL_FRONT_LEFT; pChannelMap[0] = MA_CHANNEL_FRONT_LEFT;
channelMap[1] = MA_CHANNEL_FRONT_RIGHT; pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT;
channelMap[2] = MA_CHANNEL_BACK_LEFT; pChannelMap[2] = MA_CHANNEL_BACK_LEFT;
channelMap[3] = MA_CHANNEL_BACK_RIGHT; pChannelMap[3] = MA_CHANNEL_BACK_RIGHT;
} break; } break;
case 5: case 5:
{ {
channelMap[0] = MA_CHANNEL_FRONT_LEFT; pChannelMap[0] = MA_CHANNEL_FRONT_LEFT;
channelMap[1] = MA_CHANNEL_FRONT_RIGHT; pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT;
channelMap[2] = MA_CHANNEL_BACK_LEFT; pChannelMap[2] = MA_CHANNEL_BACK_LEFT;
channelMap[3] = MA_CHANNEL_BACK_RIGHT; pChannelMap[3] = MA_CHANNEL_BACK_RIGHT;
channelMap[4] = MA_CHANNEL_FRONT_CENTER; pChannelMap[4] = MA_CHANNEL_FRONT_CENTER;
} break; } break;
case 6: case 6:
default: default:
{ {
channelMap[0] = MA_CHANNEL_FRONT_LEFT; pChannelMap[0] = MA_CHANNEL_FRONT_LEFT;
channelMap[1] = MA_CHANNEL_FRONT_RIGHT; pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT;
channelMap[2] = MA_CHANNEL_BACK_LEFT; pChannelMap[2] = MA_CHANNEL_BACK_LEFT;
channelMap[3] = MA_CHANNEL_BACK_RIGHT; pChannelMap[3] = MA_CHANNEL_BACK_RIGHT;
channelMap[4] = MA_CHANNEL_FRONT_CENTER; pChannelMap[4] = MA_CHANNEL_FRONT_CENTER;
channelMap[5] = MA_CHANNEL_LFE; pChannelMap[5] = MA_CHANNEL_LFE;
} break; } break;
} }
/* Remainder. */ /* Remainder. */
if (channels > 6) { if (channels > 6) {
ma_uint32 iChannel; ma_uint32 iChannel;
for (iChannel = 6; iChannel < MA_MAX_CHANNELS; ++iChannel) { for (iChannel = 6; iChannel < channels && iChannel < MA_MAX_CHANNELS; ++iChannel) {
channelMap[iChannel] = (ma_channel)(MA_CHANNEL_AUX_0 + (iChannel-6)); if (iChannel < MA_MAX_CHANNELS) {
pChannelMap[iChannel] = (ma_channel)(MA_CHANNEL_AUX_0 + (iChannel-6));
} else {
pChannelMap[iChannel] = MA_CHANNEL_NONE;
}
} }
} }
} }
MA_API void ma_get_standard_channel_map(ma_standard_channel_map standardChannelMap, ma_uint32 channels, ma_channel channelMap[MA_MAX_CHANNELS]) MA_API void ma_get_standard_channel_map(ma_standard_channel_map standardChannelMap, ma_uint32 channels, ma_channel* pChannelMap)
{ {
switch (standardChannelMap) switch (standardChannelMap)
{ {
case ma_standard_channel_map_alsa: case ma_standard_channel_map_alsa:
{ {
ma_get_standard_channel_map_alsa(channels, channelMap); ma_get_standard_channel_map_alsa(channels, pChannelMap);
} break; } break;
case ma_standard_channel_map_rfc3551: case ma_standard_channel_map_rfc3551:
{ {
ma_get_standard_channel_map_rfc3551(channels, channelMap); ma_get_standard_channel_map_rfc3551(channels, pChannelMap);
} break; } break;
case ma_standard_channel_map_flac: case ma_standard_channel_map_flac:
{ {
ma_get_standard_channel_map_flac(channels, channelMap); ma_get_standard_channel_map_flac(channels, pChannelMap);
} break; } break;
case ma_standard_channel_map_vorbis: case ma_standard_channel_map_vorbis:
{ {
ma_get_standard_channel_map_vorbis(channels, channelMap); ma_get_standard_channel_map_vorbis(channels, pChannelMap);
} break; } break;
case ma_standard_channel_map_sound4: case ma_standard_channel_map_sound4:
{ {
ma_get_standard_channel_map_sound4(channels, channelMap); ma_get_standard_channel_map_sound4(channels, pChannelMap);
} break; } break;
case ma_standard_channel_map_sndio: case ma_standard_channel_map_sndio:
{ {
ma_get_standard_channel_map_sndio(channels, channelMap); ma_get_standard_channel_map_sndio(channels, pChannelMap);
} break; } break;
case ma_standard_channel_map_microsoft: case ma_standard_channel_map_microsoft:
default: default:
{ {
ma_get_standard_channel_map_microsoft(channels, channelMap); ma_get_standard_channel_map_microsoft(channels, pChannelMap);
} break; } break;
} }
} }
...@@ -39829,9 +39912,9 @@ MA_API void ma_channel_map_copy(ma_channel* pOut, const ma_channel* pIn, ma_uint ...@@ -39829,9 +39912,9 @@ MA_API void ma_channel_map_copy(ma_channel* pOut, const ma_channel* pIn, ma_uint
} }
} }
MA_API ma_bool32 ma_channel_map_valid(ma_uint32 channels, const ma_channel channelMap[MA_MAX_CHANNELS]) MA_API ma_bool32 ma_channel_map_valid(ma_uint32 channels, const ma_channel* pChannelMap)
{ {
if (channelMap == NULL) { if (pChannelMap == NULL) {
return MA_FALSE; return MA_FALSE;
} }
...@@ -39844,7 +39927,7 @@ MA_API ma_bool32 ma_channel_map_valid(ma_uint32 channels, const ma_channel chann ...@@ -39844,7 +39927,7 @@ MA_API ma_bool32 ma_channel_map_valid(ma_uint32 channels, const ma_channel chann
if (channels > 1) { if (channels > 1) {
ma_uint32 iChannel; ma_uint32 iChannel;
for (iChannel = 0; iChannel < channels; ++iChannel) { for (iChannel = 0; iChannel < channels; ++iChannel) {
if (channelMap[iChannel] == MA_CHANNEL_MONO) { if (pChannelMap[iChannel] == MA_CHANNEL_MONO) {
return MA_FALSE; return MA_FALSE;
} }
} }
...@@ -39853,20 +39936,16 @@ MA_API ma_bool32 ma_channel_map_valid(ma_uint32 channels, const ma_channel chann ...@@ -39853,20 +39936,16 @@ MA_API ma_bool32 ma_channel_map_valid(ma_uint32 channels, const ma_channel chann
return MA_TRUE; return MA_TRUE;
} }
MA_API ma_bool32 ma_channel_map_equal(ma_uint32 channels, const ma_channel channelMapA[MA_MAX_CHANNELS], const ma_channel channelMapB[MA_MAX_CHANNELS]) MA_API ma_bool32 ma_channel_map_equal(ma_uint32 channels, const ma_channel* pChannelMapA, const ma_channel* pChannelMapB)
{ {
ma_uint32 iChannel; ma_uint32 iChannel;
if (channelMapA == channelMapB) { if (pChannelMapA == pChannelMapB) {
return MA_FALSE; return MA_TRUE;
}
if (channels == 0 || channels > MA_MAX_CHANNELS) {
return MA_FALSE;
} }
for (iChannel = 0; iChannel < channels; ++iChannel) { for (iChannel = 0; iChannel < channels; ++iChannel) {
if (channelMapA[iChannel] != channelMapB[iChannel]) { if (pChannelMapA[iChannel] != pChannelMapB[iChannel]) {
return MA_FALSE; return MA_FALSE;
} }
} }
...@@ -39874,12 +39953,12 @@ MA_API ma_bool32 ma_channel_map_equal(ma_uint32 channels, const ma_channel chann ...@@ -39874,12 +39953,12 @@ MA_API ma_bool32 ma_channel_map_equal(ma_uint32 channels, const ma_channel chann
return MA_TRUE; return MA_TRUE;
} }
MA_API ma_bool32 ma_channel_map_blank(ma_uint32 channels, const ma_channel channelMap[MA_MAX_CHANNELS]) MA_API ma_bool32 ma_channel_map_blank(ma_uint32 channels, const ma_channel* pChannelMap)
{ {
ma_uint32 iChannel; ma_uint32 iChannel;
for (iChannel = 0; iChannel < channels; ++iChannel) { for (iChannel = 0; iChannel < channels; ++iChannel) {
if (channelMap[iChannel] != MA_CHANNEL_NONE) { if (pChannelMap[iChannel] != MA_CHANNEL_NONE) {
return MA_FALSE; return MA_FALSE;
} }
} }
...@@ -39887,11 +39966,12 @@ MA_API ma_bool32 ma_channel_map_blank(ma_uint32 channels, const ma_channel chann ...@@ -39887,11 +39966,12 @@ MA_API ma_bool32 ma_channel_map_blank(ma_uint32 channels, const ma_channel chann
return MA_TRUE; return MA_TRUE;
} }
MA_API ma_bool32 ma_channel_map_contains_channel_position(ma_uint32 channels, const ma_channel channelMap[MA_MAX_CHANNELS], ma_channel channelPosition) MA_API ma_bool32 ma_channel_map_contains_channel_position(ma_uint32 channels, const ma_channel* pChannelMap, ma_channel channelPosition)
{ {
ma_uint32 iChannel; ma_uint32 iChannel;
for (iChannel = 0; iChannel < channels; ++iChannel) { for (iChannel = 0; iChannel < channels; ++iChannel) {
if (channelMap[iChannel] == channelPosition) { if (pChannelMap[iChannel] == channelPosition) {
return MA_TRUE; return MA_TRUE;
} }
} }
...@@ -43076,8 +43156,8 @@ MA_API ma_decoder_config ma_decoder_config_init(ma_format outputFormat, ma_uint3 ...@@ -43076,8 +43156,8 @@ MA_API ma_decoder_config ma_decoder_config_init(ma_format outputFormat, ma_uint3
{ {
ma_decoder_config config; ma_decoder_config config;
MA_ZERO_OBJECT(&config); MA_ZERO_OBJECT(&config);
config.format = outputFormat; config.format = outputFormat;
config.channels = outputChannels; config.channels = ma_min(outputChannels, ma_countof(config.channelMap));
config.sampleRate = outputSampleRate; config.sampleRate = outputSampleRate;
config.resampling.algorithm = ma_resample_algorithm_linear; config.resampling.algorithm = ma_resample_algorithm_linear;
config.resampling.linear.lpfOrder = ma_min(MA_DEFAULT_RESAMPLER_LPF_ORDER, MA_MAX_FILTER_ORDER); config.resampling.linear.lpfOrder = ma_min(MA_DEFAULT_RESAMPLER_LPF_ORDER, MA_MAX_FILTER_ORDER);
...@@ -43105,6 +43185,18 @@ static ma_result ma_decoder__init_data_converter(ma_decoder* pDecoder, const ma_ ...@@ -43105,6 +43185,18 @@ static ma_result ma_decoder__init_data_converter(ma_decoder* pDecoder, const ma_
ma_data_converter_config converterConfig; ma_data_converter_config converterConfig;
MA_ASSERT(pDecoder != NULL); MA_ASSERT(pDecoder != NULL);
MA_ASSERT(pConfig != NULL);
/* Make sure we're not asking for too many channels. */
if (pConfig->channels > MA_MAX_CHANNELS) {
return MA_INVALID_ARGS;
}
/* The internal channels should have already been validated at a higher level, but we'll do it again explicitly here for safety. */
if (pDecoder->internalChannels > MA_MAX_CHANNELS) {
return MA_INVALID_ARGS;
}
/* Output format. */ /* Output format. */
if (pConfig->format == ma_format_unknown) { if (pConfig->format == ma_format_unknown) {
...@@ -46134,6 +46226,10 @@ MA_API ma_result ma_noise_init(const ma_noise_config* pConfig, ma_noise* pNoise) ...@@ -46134,6 +46226,10 @@ MA_API ma_result ma_noise_init(const ma_noise_config* pConfig, ma_noise* pNoise)
return MA_INVALID_ARGS; return MA_INVALID_ARGS;
} }
if (pConfig->channels < MA_MIN_CHANNELS || pConfig->channels > MA_MAX_CHANNELS) {
return MA_INVALID_ARGS;
}
pNoise->ds.onRead = ma_noise__data_source_on_read; pNoise->ds.onRead = ma_noise__data_source_on_read;
pNoise->ds.onSeek = ma_noise__data_source_on_seek; /* <-- No-op for noise. */ pNoise->ds.onSeek = ma_noise__data_source_on_seek; /* <-- No-op for noise. */
pNoise->ds.onGetDataFormat = ma_noise__data_source_on_get_data_format; pNoise->ds.onGetDataFormat = ma_noise__data_source_on_get_data_format;
...@@ -61835,6 +61931,9 @@ The following miscellaneous changes have also been made. ...@@ -61835,6 +61931,9 @@ The following miscellaneous changes have also been made.
/* /*
REVISION HISTORY REVISION HISTORY
================ ================
v0.10.13 - TBD
- Fix some potential buffer overflow errors with channel maps when channel counts are greater than MA_MAX_CHANNELS.
v0.10.12 - 2020-07-04 v0.10.12 - 2020-07-04
- Fix compilation errors on the iOS build. - Fix compilation errors on the iOS build.
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