From 0e3549310ae82326e991778aae5dd3e70fbe4749 Mon Sep 17 00:00:00 2001 From: David Reid Date: Sat, 11 Jul 2020 11:36:57 +1000 Subject: [PATCH] Version 0.10.13 --- extras/miniaudio_split/miniaudio.c | 948 ++++++++++++++++------------- extras/miniaudio_split/miniaudio.h | 47 +- miniaudio.h | 4 +- 3 files changed, 564 insertions(+), 435 deletions(-) diff --git a/extras/miniaudio_split/miniaudio.c b/extras/miniaudio_split/miniaudio.c index c141e113..ad690d70 100644 --- a/extras/miniaudio_split/miniaudio.c +++ b/extras/miniaudio_split/miniaudio.c @@ -1,6 +1,6 @@ /* 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 - 2020-07-11 David Reid - davidreidsoftware@gmail.com @@ -506,7 +506,6 @@ static void ma_sleep(ma_uint32 milliseconds) } #endif -#if !defined(MA_EMSCRIPTEN) static MA_INLINE void ma_yield() { #if defined(__i386) || defined(_M_IX86) || defined(__x86_64__) || defined(_M_X64) @@ -532,7 +531,6 @@ static MA_INLINE void ma_yield() /* Unknown or unsupported architecture. No-op. */ #endif } -#endif @@ -2670,50 +2668,6 @@ c89atomic_bool c89atomic_compare_exchange_strong_explicit_64(volatile c89atomic_ /* c89atomic.h end */ -typedef unsigned char ma_spinlock; - -static MA_INLINE ma_result ma_spinlock_lock_ex(ma_spinlock* pSpinlock, ma_bool32 yield) -{ - if (pSpinlock == NULL) { - return MA_INVALID_ARGS; - } - - for (;;) { - if (c89atomic_flag_test_and_set_explicit(pSpinlock, c89atomic_memory_order_acquire) == 0) { - break; - } - - while (c89atomic_load_explicit_8(pSpinlock, c89atomic_memory_order_relaxed) == 1) { - if (yield) { - ma_yield(); - } - } - } - - return MA_SUCCESS; -} - -static ma_result ma_spinlock_lock(ma_spinlock* pSpinlock) -{ - return ma_spinlock_lock_ex(pSpinlock, MA_TRUE); -} - -static ma_result ma_spinlock_lock_noyield(ma_spinlock* pSpinlock) -{ - return ma_spinlock_lock_ex(pSpinlock, MA_FALSE); -} - -static ma_result ma_spinlock_unlock(ma_spinlock* pSpinlock) -{ - if (pSpinlock == NULL) { - return MA_INVALID_ARGS; - } - - c89atomic_flag_clear_explicit(pSpinlock, c89atomic_memory_order_release); - return MA_SUCCESS; -} - - static void* ma__malloc_default(size_t sz, void* pUserData) { @@ -2907,6 +2861,47 @@ Threading #endif typedef ma_thread_result (MA_THREADCALL * ma_thread_entry_proc)(void* pData); +static MA_INLINE ma_result ma_spinlock_lock_ex(ma_spinlock* pSpinlock, ma_bool32 yield) +{ + if (pSpinlock == NULL) { + return MA_INVALID_ARGS; + } + + for (;;) { + if (c89atomic_flag_test_and_set_explicit(pSpinlock, c89atomic_memory_order_acquire) == 0) { + break; + } + + while (c89atomic_load_explicit_8(pSpinlock, c89atomic_memory_order_relaxed) == 1) { + if (yield) { + ma_yield(); + } + } + } + + return MA_SUCCESS; +} + +MA_API ma_result ma_spinlock_lock(ma_spinlock* pSpinlock) +{ + return ma_spinlock_lock_ex(pSpinlock, MA_TRUE); +} + +MA_API ma_result ma_spinlock_lock_noyield(ma_spinlock* pSpinlock) +{ + return ma_spinlock_lock_ex(pSpinlock, MA_FALSE); +} + +MA_API ma_result ma_spinlock_unlock(ma_spinlock* pSpinlock) +{ + if (pSpinlock == NULL) { + return MA_INVALID_ARGS; + } + + c89atomic_flag_clear_explicit(pSpinlock, c89atomic_memory_order_release); + return MA_SUCCESS; +} + #ifdef MA_WIN32 static int ma_thread_priority_to_win32(ma_thread_priority priority) { @@ -3109,6 +3104,10 @@ static ma_result ma_thread_create__posix(ma_thread* pThread, ma_thread_priority pthread_attr_destroy(&attr); } +#else + /* It's the emscripten build. We'll have a few unused parameters. */ + (void)priority; + (void)stackSize; #endif result = pthread_create(pThread, pAttr, entryProc, pData); @@ -4896,7 +4895,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); pDevice->capture.internalFormat = pConfig->capture.format; 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.internalPeriods = pConfig->periods; } @@ -4904,7 +4903,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); pDevice->playback.internalFormat = pConfig->playback.format; 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.internalPeriods = pConfig->periods; } @@ -5453,39 +5452,39 @@ static DWORD ma_channel_id_to_win32(DWORD id) } /* 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; ma_uint32 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; } /* 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) { - channelMap[0] = MA_CHANNEL_MONO; + pChannelMap[0] = MA_CHANNEL_MONO; } else if (channels == 2 && dwChannelMask == 0) { - channelMap[0] = MA_CHANNEL_FRONT_LEFT; - channelMap[1] = MA_CHANNEL_FRONT_RIGHT; + pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; + pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT; } else { if (channels == 1 && (dwChannelMask & SPEAKER_FRONT_CENTER) != 0) { - channelMap[0] = MA_CHANNEL_MONO; + pChannelMap[0] = MA_CHANNEL_MONO; } else { /* Just iterate over each bit. */ ma_uint32 iChannel = 0; ma_uint32 iBit; - for (iBit = 0; iBit < 32; ++iBit) { + for (iBit = 0; iBit < 32 && iBit < channels; ++iBit) { DWORD bitValue = (dwChannelMask & (1UL << iBit)); if (bitValue != 0) { /* The bit is set. */ - channelMap[iChannel] = ma_channel_id_to_ma__win32(bitValue); + pChannelMap[iChannel] = ma_channel_id_to_ma__win32(bitValue); iChannel += 1; } } @@ -6416,6 +6415,11 @@ static ma_result ma_context_get_device_info_from_IAudioClient__wasapi(ma_context ma_bool32 found; 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_ZERO_OBJECT(&wf); @@ -13160,7 +13164,7 @@ static ma_result ma_device_init_by_type__alsa(ma_context* pContext, const ma_dev pDevice->capture.internalFormat = internalFormat; pDevice->capture.internalChannels = internalChannels; 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.internalPeriods = internalPeriods; } else { @@ -13169,7 +13173,7 @@ static ma_result ma_device_init_by_type__alsa(ma_context* pContext, const ma_dev pDevice->playback.internalFormat = internalFormat; pDevice->playback.internalChannels = internalChannels; 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.internalPeriods = internalPeriods; } @@ -17045,14 +17049,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); if (pChannelLayout->mChannelLayoutTag == kAudioChannelLayoutTag_UseChannelDescriptions) { UInt32 iChannel; - for (iChannel = 0; iChannel < pChannelLayout->mNumberChannelDescriptions; ++iChannel) { - channelMap[iChannel] = ma_channel_from_AudioChannelLabel(pChannelLayout->mChannelDescriptions[iChannel].mChannelLabel); + for (iChannel = 0; iChannel < pChannelLayout->mNumberChannelDescriptions && iChannel < channelMapCap; ++iChannel) { + pChannelMap[iChannel] = ma_channel_from_AudioChannelLabel(pChannelLayout->mChannelDescriptions[iChannel].mChannelLabel); } } else #if 0 @@ -17061,10 +17065,10 @@ static ma_result ma_get_channel_map_from_AudioChannelLayout(AudioChannelLayout* UInt32 iChannel = 0; UInt32 iBit; AudioChannelBitmap bitmap = pChannelLayout->mChannelBitmap; - for (iBit = 0; iBit < 32; ++iBit) { + for (iBit = 0; iBit < 32 && iBit < channelMapCap; ++iBit) { AudioChannelBitmap bit = bitmap & (1 << iBit); if (bit != 0) { - channelMap[iChannel++] = ma_channel_from_AudioChannelBit(bit); + pChannelMap[iChannel++] = ma_channel_from_AudioChannelBit(bit); } } } else @@ -17074,7 +17078,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 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) { case kAudioChannelLayoutTag_Mono: @@ -17086,35 +17091,35 @@ static ma_result ma_get_channel_map_from_AudioChannelLayout(AudioChannelLayout* case kAudioChannelLayoutTag_Binaural: 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; case kAudioChannelLayoutTag_Octagonal: { - channelMap[7] = MA_CHANNEL_SIDE_RIGHT; - channelMap[6] = MA_CHANNEL_SIDE_LEFT; + pChannelMap[7] = MA_CHANNEL_SIDE_RIGHT; + pChannelMap[6] = MA_CHANNEL_SIDE_LEFT; } /* Intentional fallthrough. */ case kAudioChannelLayoutTag_Hexagonal: { - channelMap[5] = MA_CHANNEL_BACK_CENTER; + pChannelMap[5] = MA_CHANNEL_BACK_CENTER; } /* Intentional fallthrough. */ case kAudioChannelLayoutTag_Pentagonal: { - channelMap[4] = MA_CHANNEL_FRONT_CENTER; + pChannelMap[4] = MA_CHANNEL_FRONT_CENTER; } /* Intentional fallghrough. */ case kAudioChannelLayoutTag_Quadraphonic: { - channelMap[3] = MA_CHANNEL_BACK_RIGHT; - channelMap[2] = MA_CHANNEL_BACK_LEFT; - channelMap[1] = MA_CHANNEL_RIGHT; - channelMap[0] = MA_CHANNEL_LEFT; + pChannelMap[3] = MA_CHANNEL_BACK_RIGHT; + pChannelMap[2] = MA_CHANNEL_BACK_LEFT; + pChannelMap[1] = MA_CHANNEL_RIGHT; + pChannelMap[0] = MA_CHANNEL_LEFT; } break; /* TODO: Add support for more tags here. */ 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; } } @@ -17387,7 +17392,7 @@ static ma_result ma_get_AudioObject_channel_count(ma_context* pContext, AudioObj } #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; ma_result result; @@ -17399,7 +17404,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? */ } - result = ma_get_channel_map_from_AudioChannelLayout(pChannelLayout, channelMap); + result = ma_get_channel_map_from_AudioChannelLayout(pChannelLayout, pChannelMap, channelMapCap); if (result != MA_SUCCESS) { ma_free(pChannelLayout, &pContext->allocationCallbacks); return result; @@ -17879,7 +17884,7 @@ static ma_result ma_find_best_format__coreaudio(ma_context* pContext, AudioObjec 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; AudioUnitElement deviceBus; @@ -17914,7 +17919,7 @@ static ma_result ma_get_AudioUnit_channel_map(ma_context* pContext, AudioUnit au 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) { ma__free_from_callbacks(pChannelLayout, &pContext->allocationCallbacks); return result; @@ -18221,6 +18226,7 @@ static OSStatus ma_on_output__coreaudio(void* pUserData, AudioUnitRenderActionFl } } else { /* 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 @@ -18343,6 +18349,7 @@ static OSStatus ma_on_input__coreaudio(void* pUserData, AudioUnitRenderActionFla } } 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. */ + 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 @@ -19009,6 +19016,11 @@ static ma_result ma_device_init_internal__coreaudio(ma_context* pContext, ma_dev pData->channelsOut = bestFormat.mChannelsPerFrame; 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 @@ -19018,11 +19030,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. */ #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 0 /* 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) { return result; } @@ -23200,7 +23212,7 @@ static SLuint32 ma_channel_id_to_opensl(ma_uint8 id) } /* 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; ma_uint32 iChannel; @@ -23212,7 +23224,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. */ -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) { channelMap[0] = MA_CHANNEL_MONO; @@ -23226,7 +23238,7 @@ static void ma_channel_mask_to_channel_map__opensl(SLuint32 channelMask, ma_uint /* Just iterate over each bit. */ ma_uint32 iChannel = 0; ma_uint32 iBit; - for (iBit = 0; iBit < 32; ++iBit) { + for (iBit = 0; iBit < 32 && iBit < channels; ++iBit) { SLuint32 bitValue = (channelMask & (1UL << iBit)); if (bitValue != 0) { /* The bit is set. */ @@ -23678,7 +23690,7 @@ static ma_result ma_SLDataFormat_PCM_init__opensl(ma_format format, ma_uint32 ch 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; #if defined(MA_ANDROID) && __ANDROID_API__ >= 21 @@ -23705,7 +23717,7 @@ static ma_result ma_deconstruct_SLDataFormat_PCM__opensl(ma_SLDataFormat_PCM* pD *pChannels = pDataFormat->numChannels; *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; } @@ -23813,7 +23825,7 @@ static ma_result ma_device_init__opensl(ma_context* pContext, const ma_device_co } /* 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. */ periodSizeInFrames = pConfig->periodSizeInFrames; @@ -23916,7 +23928,7 @@ static ma_result ma_device_init__opensl(ma_context* pContext, const ma_device_co } /* 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. */ periodSizeInFrames = pConfig->periodSizeInFrames; @@ -24354,10 +24366,22 @@ static ma_result ma_device_init_by_type__webaudio(ma_context* pContext, const ma return MA_NO_DEVICE; } - /* Try calculating an appropriate buffer size. */ + /* + Try calculating an appropriate buffer size. There have been reports of the default buffer size being too small on some browsers. If we're using default buffer size, we'll make sure + the period size is a big biffer than our standard defaults. + */ internalPeriodSizeInFrames = pConfig->periodSizeInFrames; if (internalPeriodSizeInFrames == 0) { - internalPeriodSizeInFrames = ma_calculate_buffer_size_in_frames_from_milliseconds(pConfig->periodSizeInMilliseconds, pConfig->sampleRate); + ma_uint32 periodSizeInMilliseconds = pConfig->periodSizeInMilliseconds; + if (pDevice->usingDefaultBufferSize) { + if (pConfig->performanceProfile == ma_performance_profile_low_latency) { + periodSizeInMilliseconds = 33; /* 1 frame @ 30 FPS */ + } else { + periodSizeInMilliseconds = 333; + } + } + + internalPeriodSizeInFrames = ma_calculate_buffer_size_in_frames_from_milliseconds(periodSizeInMilliseconds, pConfig->sampleRate); } /* The size of the buffer must be a power of 2 and between 256 and 16384. */ @@ -24765,8 +24789,8 @@ static ma_bool32 ma__is_channel_map_valid(const ma_channel* channelMap, ma_uint3 if (channelMap[0] != MA_CHANNEL_NONE) { ma_uint32 iChannel; - if (channels == 0) { - return MA_FALSE; /* No channels. */ + if (channels == 0 || channels > MA_MAX_CHANNELS) { + return MA_FALSE; /* Channel count out of range. */ } /* A channel cannot be present in the channel map more than once. */ @@ -24798,6 +24822,7 @@ static ma_result ma_device__post_init_setup(ma_device* pDevice, ma_device_type d pDevice->capture.channels = pDevice->capture.internalChannels; } if (pDevice->capture.usingDefaultChannelMap) { + MA_ASSERT(pDevice->capture.channels <= MA_MAX_CHANNELS); if (pDevice->capture.internalChannels == pDevice->capture.channels) { ma_channel_map_copy(pDevice->capture.channelMap, pDevice->capture.internalChannelMap, pDevice->capture.channels); } else { @@ -24814,6 +24839,7 @@ static ma_result ma_device__post_init_setup(ma_device* pDevice, ma_device_type d pDevice->playback.channels = pDevice->playback.internalChannels; } if (pDevice->playback.usingDefaultChannelMap) { + MA_ASSERT(pDevice->playback.channels <= MA_MAX_CHANNELS); if (pDevice->playback.internalChannels == pDevice->playback.channels) { ma_channel_map_copy(pDevice->playback.channelMap, pDevice->playback.internalChannelMap, pDevice->playback.channels); } else { @@ -24830,18 +24856,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) { /* Converting from internal device format to client format. */ ma_data_converter_config converterConfig = ma_data_converter_config_init_default(); converterConfig.formatIn = pDevice->capture.internalFormat; converterConfig.channelsIn = pDevice->capture.internalChannels; 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.channelsOut = pDevice->capture.channels; 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.algorithm = pDevice->resampling.algorithm; converterConfig.resampling.linear.lpfOrder = pDevice->resampling.linear.lpfOrder; @@ -24859,11 +24885,11 @@ static ma_result ma_device__post_init_setup(ma_device* pDevice, ma_device_type d converterConfig.formatIn = pDevice->playback.format; converterConfig.channelsIn = pDevice->playback.channels; 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.channelsOut = pDevice->playback.internalChannels; 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.algorithm = pDevice->resampling.algorithm; converterConfig.resampling.linear.lpfOrder = pDevice->resampling.linear.lpfOrder; @@ -25627,7 +25653,8 @@ MA_API ma_result ma_device_init(ma_context* pContext, const ma_device_config* pC 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->sampleRate = config.sampleRate; @@ -28723,6 +28750,10 @@ MA_API ma_result ma_biquad_init(const ma_biquad_config* pConfig, ma_biquad* pBQ) 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); } @@ -28930,6 +28961,10 @@ MA_API ma_result ma_lpf1_init(const ma_lpf1_config* pConfig, ma_lpf1* pLPF) 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); } @@ -29432,6 +29467,10 @@ MA_API ma_result ma_hpf1_init(const ma_hpf1_config* pConfig, ma_hpf1* pHPF) 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); } @@ -30787,6 +30826,10 @@ MA_API ma_result ma_linear_resampler_init(const ma_linear_resampler_config* pCon return MA_INVALID_ARGS; } + if (pConfig->channels < MA_MIN_CHANNELS || pConfig->channels > MA_MAX_CHANNELS) { + return MA_INVALID_ARGS; + } + pResampler->config = *pConfig; /* Setting the rate will set up the filter and time advances for us. */ @@ -31971,15 +32014,20 @@ static float ma_calculate_channel_position_rectangular_weight(ma_channel channel 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; + + /* 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); config.format = format; config.channelsIn = channelsIn; config.channelsOut = channelsOut; - ma_channel_map_copy(config.channelMapIn, channelMapIn, channelsIn); - ma_channel_map_copy(config.channelMapOut, channelMapOut, channelsOut); + ma_channel_map_copy(config.channelMapIn, pChannelMapIn, channelsIn); + ma_channel_map_copy(config.channelMapOut, pChannelMapOut, channelsOut); config.mixingMode = mixingMode; return config; @@ -32022,6 +32070,12 @@ MA_API ma_result ma_channel_converter_init(const ma_channel_converter_config* pC 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)) { return MA_INVALID_ARGS; /* Invalid input channel map. */ } @@ -32739,11 +32793,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_data_converter_config config = ma_data_converter_config_init_default(); - config.formatIn = formatIn; - config.formatOut = formatOut; - config.channelsIn = channelsIn; - config.channelsOut = channelsOut; - config.sampleRateIn = sampleRateIn; + config.formatIn = formatIn; + config.formatOut = formatOut; + config.channelsIn = ma_min(channelsIn, MA_MAX_CHANNELS); + config.channelsOut = ma_min(channelsOut, MA_MAX_CHANNELS); + config.sampleRateIn = sampleRateIn; config.sampleRateOut = sampleRateOut; return config; @@ -33643,396 +33697,499 @@ MA_API ma_uint64 ma_data_converter_get_output_latency(ma_data_converter* pConver 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 */ switch (channels) { case 1: { - channelMap[0] = MA_CHANNEL_MONO; + pChannelMap[0] = MA_CHANNEL_MONO; } break; case 2: { - channelMap[0] = MA_CHANNEL_FRONT_LEFT; - channelMap[1] = MA_CHANNEL_FRONT_RIGHT; + pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; + pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT; } break; case 3: /* Not defined, but best guess. */ { - channelMap[0] = MA_CHANNEL_FRONT_LEFT; - channelMap[1] = MA_CHANNEL_FRONT_RIGHT; - channelMap[2] = MA_CHANNEL_FRONT_CENTER; + pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; + pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT; + pChannelMap[2] = MA_CHANNEL_FRONT_CENTER; } break; case 4: { #ifndef MA_USE_QUAD_MICROSOFT_CHANNEL_MAP /* Surround. Using the Surround profile has the advantage of the 3rd channel (MA_CHANNEL_FRONT_CENTER) mapping nicely with higher channel counts. */ - channelMap[0] = MA_CHANNEL_FRONT_LEFT; - channelMap[1] = MA_CHANNEL_FRONT_RIGHT; - channelMap[2] = MA_CHANNEL_FRONT_CENTER; - channelMap[3] = MA_CHANNEL_BACK_CENTER; + pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; + pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT; + pChannelMap[2] = MA_CHANNEL_FRONT_CENTER; + pChannelMap[3] = MA_CHANNEL_BACK_CENTER; #else /* Quad. */ - channelMap[0] = MA_CHANNEL_FRONT_LEFT; - channelMap[1] = MA_CHANNEL_FRONT_RIGHT; - channelMap[2] = MA_CHANNEL_BACK_LEFT; - channelMap[3] = MA_CHANNEL_BACK_RIGHT; + pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; + pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT; + pChannelMap[2] = MA_CHANNEL_BACK_LEFT; + pChannelMap[3] = MA_CHANNEL_BACK_RIGHT; #endif } break; case 5: /* Not defined, but best guess. */ { - channelMap[0] = MA_CHANNEL_FRONT_LEFT; - channelMap[1] = MA_CHANNEL_FRONT_RIGHT; - channelMap[2] = MA_CHANNEL_FRONT_CENTER; - channelMap[3] = MA_CHANNEL_BACK_LEFT; - channelMap[4] = MA_CHANNEL_BACK_RIGHT; + pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; + pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT; + pChannelMap[2] = MA_CHANNEL_FRONT_CENTER; + pChannelMap[3] = MA_CHANNEL_BACK_LEFT; + pChannelMap[4] = MA_CHANNEL_BACK_RIGHT; } break; case 6: { - channelMap[0] = MA_CHANNEL_FRONT_LEFT; - channelMap[1] = MA_CHANNEL_FRONT_RIGHT; - channelMap[2] = MA_CHANNEL_FRONT_CENTER; - channelMap[3] = MA_CHANNEL_LFE; - channelMap[4] = MA_CHANNEL_SIDE_LEFT; - channelMap[5] = MA_CHANNEL_SIDE_RIGHT; + pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; + pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT; + pChannelMap[2] = MA_CHANNEL_FRONT_CENTER; + pChannelMap[3] = MA_CHANNEL_LFE; + pChannelMap[4] = MA_CHANNEL_SIDE_LEFT; + pChannelMap[5] = MA_CHANNEL_SIDE_RIGHT; } break; case 7: /* Not defined, but best guess. */ { - channelMap[0] = MA_CHANNEL_FRONT_LEFT; - channelMap[1] = MA_CHANNEL_FRONT_RIGHT; - channelMap[2] = MA_CHANNEL_FRONT_CENTER; - channelMap[3] = MA_CHANNEL_LFE; - channelMap[4] = MA_CHANNEL_BACK_CENTER; - channelMap[5] = MA_CHANNEL_SIDE_LEFT; - channelMap[6] = MA_CHANNEL_SIDE_RIGHT; + pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; + pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT; + pChannelMap[2] = MA_CHANNEL_FRONT_CENTER; + pChannelMap[3] = MA_CHANNEL_LFE; + pChannelMap[4] = MA_CHANNEL_BACK_CENTER; + pChannelMap[5] = MA_CHANNEL_SIDE_LEFT; + pChannelMap[6] = MA_CHANNEL_SIDE_RIGHT; } break; case 8: default: { - channelMap[0] = MA_CHANNEL_FRONT_LEFT; - channelMap[1] = MA_CHANNEL_FRONT_RIGHT; - channelMap[2] = MA_CHANNEL_FRONT_CENTER; - channelMap[3] = MA_CHANNEL_LFE; - channelMap[4] = MA_CHANNEL_BACK_LEFT; - channelMap[5] = MA_CHANNEL_BACK_RIGHT; - channelMap[6] = MA_CHANNEL_SIDE_LEFT; - channelMap[7] = MA_CHANNEL_SIDE_RIGHT; + pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; + pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT; + pChannelMap[2] = MA_CHANNEL_FRONT_CENTER; + pChannelMap[3] = MA_CHANNEL_LFE; + pChannelMap[4] = MA_CHANNEL_BACK_LEFT; + pChannelMap[5] = MA_CHANNEL_BACK_RIGHT; + pChannelMap[6] = MA_CHANNEL_SIDE_LEFT; + pChannelMap[7] = MA_CHANNEL_SIDE_RIGHT; } break; } /* Remainder. */ if (channels > 8) { ma_uint32 iChannel; - for (iChannel = 8; iChannel < MA_MAX_CHANNELS; ++iChannel) { - channelMap[iChannel] = (ma_channel)(MA_CHANNEL_AUX_0 + (iChannel-8)); + for (iChannel = 8; iChannel < channels; ++iChannel) { + 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) { case 1: { - channelMap[0] = MA_CHANNEL_MONO; + pChannelMap[0] = MA_CHANNEL_MONO; } break; case 2: { - channelMap[0] = MA_CHANNEL_LEFT; - channelMap[1] = MA_CHANNEL_RIGHT; + pChannelMap[0] = MA_CHANNEL_LEFT; + pChannelMap[1] = MA_CHANNEL_RIGHT; } break; case 3: { - channelMap[0] = MA_CHANNEL_FRONT_LEFT; - channelMap[1] = MA_CHANNEL_FRONT_RIGHT; - channelMap[2] = MA_CHANNEL_FRONT_CENTER; + pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; + pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT; + pChannelMap[2] = MA_CHANNEL_FRONT_CENTER; } break; case 4: { - channelMap[0] = MA_CHANNEL_FRONT_LEFT; - channelMap[1] = MA_CHANNEL_FRONT_RIGHT; - channelMap[2] = MA_CHANNEL_BACK_LEFT; - channelMap[3] = MA_CHANNEL_BACK_RIGHT; + pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; + pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT; + pChannelMap[2] = MA_CHANNEL_BACK_LEFT; + pChannelMap[3] = MA_CHANNEL_BACK_RIGHT; } break; case 5: { - channelMap[0] = MA_CHANNEL_FRONT_LEFT; - channelMap[1] = MA_CHANNEL_FRONT_RIGHT; - channelMap[2] = MA_CHANNEL_BACK_LEFT; - channelMap[3] = MA_CHANNEL_BACK_RIGHT; - channelMap[4] = MA_CHANNEL_FRONT_CENTER; + pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; + pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT; + pChannelMap[2] = MA_CHANNEL_BACK_LEFT; + pChannelMap[3] = MA_CHANNEL_BACK_RIGHT; + pChannelMap[4] = MA_CHANNEL_FRONT_CENTER; } break; case 6: { - channelMap[0] = MA_CHANNEL_FRONT_LEFT; - channelMap[1] = MA_CHANNEL_FRONT_RIGHT; - channelMap[2] = MA_CHANNEL_BACK_LEFT; - channelMap[3] = MA_CHANNEL_BACK_RIGHT; - channelMap[4] = MA_CHANNEL_FRONT_CENTER; - channelMap[5] = MA_CHANNEL_LFE; + pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; + pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT; + pChannelMap[2] = MA_CHANNEL_BACK_LEFT; + pChannelMap[3] = MA_CHANNEL_BACK_RIGHT; + pChannelMap[4] = MA_CHANNEL_FRONT_CENTER; + pChannelMap[5] = MA_CHANNEL_LFE; } break; case 7: { - channelMap[0] = MA_CHANNEL_FRONT_LEFT; - channelMap[1] = MA_CHANNEL_FRONT_RIGHT; - channelMap[2] = MA_CHANNEL_BACK_LEFT; - channelMap[3] = MA_CHANNEL_BACK_RIGHT; - channelMap[4] = MA_CHANNEL_FRONT_CENTER; - channelMap[5] = MA_CHANNEL_LFE; - channelMap[6] = MA_CHANNEL_BACK_CENTER; + pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; + pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT; + pChannelMap[2] = MA_CHANNEL_BACK_LEFT; + pChannelMap[3] = MA_CHANNEL_BACK_RIGHT; + pChannelMap[4] = MA_CHANNEL_FRONT_CENTER; + pChannelMap[5] = MA_CHANNEL_LFE; + pChannelMap[6] = MA_CHANNEL_BACK_CENTER; } break; case 8: default: { - channelMap[0] = MA_CHANNEL_FRONT_LEFT; - channelMap[1] = MA_CHANNEL_FRONT_RIGHT; - channelMap[2] = MA_CHANNEL_BACK_LEFT; - channelMap[3] = MA_CHANNEL_BACK_RIGHT; - channelMap[4] = MA_CHANNEL_FRONT_CENTER; - channelMap[5] = MA_CHANNEL_LFE; - channelMap[6] = MA_CHANNEL_SIDE_LEFT; - channelMap[7] = MA_CHANNEL_SIDE_RIGHT; + pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; + pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT; + pChannelMap[2] = MA_CHANNEL_BACK_LEFT; + pChannelMap[3] = MA_CHANNEL_BACK_RIGHT; + pChannelMap[4] = MA_CHANNEL_FRONT_CENTER; + pChannelMap[5] = MA_CHANNEL_LFE; + pChannelMap[6] = MA_CHANNEL_SIDE_LEFT; + pChannelMap[7] = MA_CHANNEL_SIDE_RIGHT; } break; } /* Remainder. */ if (channels > 8) { ma_uint32 iChannel; - for (iChannel = 8; iChannel < MA_MAX_CHANNELS; ++iChannel) { - channelMap[iChannel] = (ma_channel)(MA_CHANNEL_AUX_0 + (iChannel-8)); + for (iChannel = 8; iChannel < channels; ++iChannel) { + 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) { case 1: { - channelMap[0] = MA_CHANNEL_MONO; + pChannelMap[0] = MA_CHANNEL_MONO; } break; case 2: { - channelMap[0] = MA_CHANNEL_LEFT; - channelMap[1] = MA_CHANNEL_RIGHT; + pChannelMap[0] = MA_CHANNEL_LEFT; + pChannelMap[1] = MA_CHANNEL_RIGHT; } break; case 3: { - channelMap[0] = MA_CHANNEL_FRONT_LEFT; - channelMap[1] = MA_CHANNEL_FRONT_RIGHT; - channelMap[2] = MA_CHANNEL_FRONT_CENTER; + pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; + pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT; + pChannelMap[2] = MA_CHANNEL_FRONT_CENTER; } break; case 4: { - channelMap[0] = MA_CHANNEL_FRONT_LEFT; - channelMap[1] = MA_CHANNEL_FRONT_CENTER; - channelMap[2] = MA_CHANNEL_FRONT_RIGHT; - channelMap[3] = MA_CHANNEL_BACK_CENTER; + pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; + pChannelMap[1] = MA_CHANNEL_FRONT_CENTER; + pChannelMap[2] = MA_CHANNEL_FRONT_RIGHT; + pChannelMap[3] = MA_CHANNEL_BACK_CENTER; } break; case 5: { - channelMap[0] = MA_CHANNEL_FRONT_LEFT; - channelMap[1] = MA_CHANNEL_FRONT_RIGHT; - channelMap[2] = MA_CHANNEL_FRONT_CENTER; - channelMap[3] = MA_CHANNEL_BACK_LEFT; - channelMap[4] = MA_CHANNEL_BACK_RIGHT; + pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; + pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT; + pChannelMap[2] = MA_CHANNEL_FRONT_CENTER; + pChannelMap[3] = MA_CHANNEL_BACK_LEFT; + pChannelMap[4] = MA_CHANNEL_BACK_RIGHT; } break; case 6: { - channelMap[0] = MA_CHANNEL_FRONT_LEFT; - channelMap[1] = MA_CHANNEL_SIDE_LEFT; - channelMap[2] = MA_CHANNEL_FRONT_CENTER; - channelMap[3] = MA_CHANNEL_FRONT_RIGHT; - channelMap[4] = MA_CHANNEL_SIDE_RIGHT; - channelMap[5] = MA_CHANNEL_BACK_CENTER; + pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; + pChannelMap[1] = MA_CHANNEL_SIDE_LEFT; + pChannelMap[2] = MA_CHANNEL_FRONT_CENTER; + pChannelMap[3] = MA_CHANNEL_FRONT_RIGHT; + pChannelMap[4] = MA_CHANNEL_SIDE_RIGHT; + pChannelMap[5] = MA_CHANNEL_BACK_CENTER; } break; } /* Remainder. */ if (channels > 8) { ma_uint32 iChannel; - for (iChannel = 6; iChannel < MA_MAX_CHANNELS; ++iChannel) { - channelMap[iChannel] = (ma_channel)(MA_CHANNEL_AUX_0 + (iChannel-6)); + for (iChannel = 6; iChannel < channels; ++iChannel) { + 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) { case 1: { - channelMap[0] = MA_CHANNEL_MONO; + pChannelMap[0] = MA_CHANNEL_MONO; } break; case 2: { - channelMap[0] = MA_CHANNEL_LEFT; - channelMap[1] = MA_CHANNEL_RIGHT; + pChannelMap[0] = MA_CHANNEL_LEFT; + pChannelMap[1] = MA_CHANNEL_RIGHT; } break; case 3: { - channelMap[0] = MA_CHANNEL_FRONT_LEFT; - channelMap[1] = MA_CHANNEL_FRONT_RIGHT; - channelMap[2] = MA_CHANNEL_FRONT_CENTER; + pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; + pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT; + pChannelMap[2] = MA_CHANNEL_FRONT_CENTER; } break; case 4: { - channelMap[0] = MA_CHANNEL_FRONT_LEFT; - channelMap[1] = MA_CHANNEL_FRONT_RIGHT; - channelMap[2] = MA_CHANNEL_BACK_LEFT; - channelMap[3] = MA_CHANNEL_BACK_RIGHT; + pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; + pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT; + pChannelMap[2] = MA_CHANNEL_BACK_LEFT; + pChannelMap[3] = MA_CHANNEL_BACK_RIGHT; } break; case 5: { - channelMap[0] = MA_CHANNEL_FRONT_LEFT; - channelMap[1] = MA_CHANNEL_FRONT_RIGHT; - channelMap[2] = MA_CHANNEL_FRONT_CENTER; - channelMap[3] = MA_CHANNEL_BACK_LEFT; - channelMap[4] = MA_CHANNEL_BACK_RIGHT; + pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; + pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT; + pChannelMap[2] = MA_CHANNEL_FRONT_CENTER; + pChannelMap[3] = MA_CHANNEL_BACK_LEFT; + pChannelMap[4] = MA_CHANNEL_BACK_RIGHT; } break; case 6: { - channelMap[0] = MA_CHANNEL_FRONT_LEFT; - channelMap[1] = MA_CHANNEL_FRONT_RIGHT; - channelMap[2] = MA_CHANNEL_FRONT_CENTER; - channelMap[3] = MA_CHANNEL_LFE; - channelMap[4] = MA_CHANNEL_BACK_LEFT; - channelMap[5] = MA_CHANNEL_BACK_RIGHT; + pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; + pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT; + pChannelMap[2] = MA_CHANNEL_FRONT_CENTER; + pChannelMap[3] = MA_CHANNEL_LFE; + pChannelMap[4] = MA_CHANNEL_BACK_LEFT; + pChannelMap[5] = MA_CHANNEL_BACK_RIGHT; } break; case 7: { - channelMap[0] = MA_CHANNEL_FRONT_LEFT; - channelMap[1] = MA_CHANNEL_FRONT_RIGHT; - channelMap[2] = MA_CHANNEL_FRONT_CENTER; - channelMap[3] = MA_CHANNEL_LFE; - channelMap[4] = MA_CHANNEL_BACK_CENTER; - channelMap[5] = MA_CHANNEL_SIDE_LEFT; - channelMap[6] = MA_CHANNEL_SIDE_RIGHT; + pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; + pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT; + pChannelMap[2] = MA_CHANNEL_FRONT_CENTER; + pChannelMap[3] = MA_CHANNEL_LFE; + pChannelMap[4] = MA_CHANNEL_BACK_CENTER; + pChannelMap[5] = MA_CHANNEL_SIDE_LEFT; + pChannelMap[6] = MA_CHANNEL_SIDE_RIGHT; } break; case 8: default: { - channelMap[0] = MA_CHANNEL_FRONT_LEFT; - channelMap[1] = MA_CHANNEL_FRONT_RIGHT; - channelMap[2] = MA_CHANNEL_FRONT_CENTER; - channelMap[3] = MA_CHANNEL_LFE; - channelMap[4] = MA_CHANNEL_BACK_LEFT; - channelMap[5] = MA_CHANNEL_BACK_RIGHT; - channelMap[6] = MA_CHANNEL_SIDE_LEFT; - channelMap[7] = MA_CHANNEL_SIDE_RIGHT; + pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; + pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT; + pChannelMap[2] = MA_CHANNEL_FRONT_CENTER; + pChannelMap[3] = MA_CHANNEL_LFE; + pChannelMap[4] = MA_CHANNEL_BACK_LEFT; + pChannelMap[5] = MA_CHANNEL_BACK_RIGHT; + pChannelMap[6] = MA_CHANNEL_SIDE_LEFT; + pChannelMap[7] = MA_CHANNEL_SIDE_RIGHT; } break; } /* Remainder. */ if (channels > 8) { ma_uint32 iChannel; - for (iChannel = 8; iChannel < MA_MAX_CHANNELS; ++iChannel) { - channelMap[iChannel] = (ma_channel)(MA_CHANNEL_AUX_0 + (iChannel-8)); + for (iChannel = 8; iChannel < channels; ++iChannel) { + 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?! */ switch (channels) { case 1: { - channelMap[0] = MA_CHANNEL_MONO; + pChannelMap[0] = MA_CHANNEL_MONO; } break; case 2: { - channelMap[0] = MA_CHANNEL_LEFT; - channelMap[1] = MA_CHANNEL_RIGHT; + pChannelMap[0] = MA_CHANNEL_LEFT; + pChannelMap[1] = MA_CHANNEL_RIGHT; } break; case 3: { - channelMap[0] = MA_CHANNEL_FRONT_LEFT; - channelMap[1] = MA_CHANNEL_FRONT_CENTER; - channelMap[2] = MA_CHANNEL_FRONT_RIGHT; + pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; + pChannelMap[1] = MA_CHANNEL_FRONT_CENTER; + pChannelMap[2] = MA_CHANNEL_FRONT_RIGHT; } break; case 4: { - channelMap[0] = MA_CHANNEL_FRONT_LEFT; - channelMap[1] = MA_CHANNEL_FRONT_RIGHT; - channelMap[2] = MA_CHANNEL_BACK_LEFT; - channelMap[3] = MA_CHANNEL_BACK_RIGHT; + pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; + pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT; + pChannelMap[2] = MA_CHANNEL_BACK_LEFT; + pChannelMap[3] = MA_CHANNEL_BACK_RIGHT; } break; case 5: { - channelMap[0] = MA_CHANNEL_FRONT_LEFT; - channelMap[1] = MA_CHANNEL_FRONT_CENTER; - channelMap[2] = MA_CHANNEL_FRONT_RIGHT; - channelMap[3] = MA_CHANNEL_BACK_LEFT; - channelMap[4] = MA_CHANNEL_BACK_RIGHT; + pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; + pChannelMap[1] = MA_CHANNEL_FRONT_CENTER; + pChannelMap[2] = MA_CHANNEL_FRONT_RIGHT; + pChannelMap[3] = MA_CHANNEL_BACK_LEFT; + pChannelMap[4] = MA_CHANNEL_BACK_RIGHT; } break; case 6: { - channelMap[0] = MA_CHANNEL_FRONT_LEFT; - channelMap[1] = MA_CHANNEL_FRONT_CENTER; - channelMap[2] = MA_CHANNEL_FRONT_RIGHT; - channelMap[3] = MA_CHANNEL_BACK_LEFT; - channelMap[4] = MA_CHANNEL_BACK_RIGHT; - channelMap[5] = MA_CHANNEL_LFE; + pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; + pChannelMap[1] = MA_CHANNEL_FRONT_CENTER; + pChannelMap[2] = MA_CHANNEL_FRONT_RIGHT; + pChannelMap[3] = MA_CHANNEL_BACK_LEFT; + pChannelMap[4] = MA_CHANNEL_BACK_RIGHT; + pChannelMap[5] = MA_CHANNEL_LFE; } break; case 7: { - channelMap[0] = MA_CHANNEL_FRONT_LEFT; - channelMap[1] = MA_CHANNEL_FRONT_CENTER; - channelMap[2] = MA_CHANNEL_FRONT_RIGHT; - channelMap[3] = MA_CHANNEL_SIDE_LEFT; - channelMap[4] = MA_CHANNEL_SIDE_RIGHT; - channelMap[5] = MA_CHANNEL_BACK_CENTER; - channelMap[6] = MA_CHANNEL_LFE; + pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; + pChannelMap[1] = MA_CHANNEL_FRONT_CENTER; + pChannelMap[2] = MA_CHANNEL_FRONT_RIGHT; + pChannelMap[3] = MA_CHANNEL_SIDE_LEFT; + pChannelMap[4] = MA_CHANNEL_SIDE_RIGHT; + pChannelMap[5] = MA_CHANNEL_BACK_CENTER; + pChannelMap[6] = MA_CHANNEL_LFE; } break; case 8: default: { - channelMap[0] = MA_CHANNEL_FRONT_LEFT; - channelMap[1] = MA_CHANNEL_FRONT_CENTER; - channelMap[2] = MA_CHANNEL_FRONT_RIGHT; - channelMap[3] = MA_CHANNEL_SIDE_LEFT; - channelMap[4] = MA_CHANNEL_SIDE_RIGHT; - channelMap[5] = MA_CHANNEL_BACK_LEFT; - channelMap[6] = MA_CHANNEL_BACK_RIGHT; - channelMap[7] = MA_CHANNEL_LFE; + pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; + pChannelMap[1] = MA_CHANNEL_FRONT_CENTER; + pChannelMap[2] = MA_CHANNEL_FRONT_RIGHT; + pChannelMap[3] = MA_CHANNEL_SIDE_LEFT; + pChannelMap[4] = MA_CHANNEL_SIDE_RIGHT; + pChannelMap[5] = MA_CHANNEL_BACK_LEFT; + pChannelMap[6] = MA_CHANNEL_BACK_RIGHT; + pChannelMap[7] = MA_CHANNEL_LFE; + } break; + } + + /* Remainder. */ + if (channels > 8) { + ma_uint32 iChannel; + for (iChannel = 8; iChannel < channels; ++iChannel) { + 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* pChannelMap) +{ + switch (channels) + { + case 1: + { + pChannelMap[0] = MA_CHANNEL_MONO; + } break; + + case 2: + { + pChannelMap[0] = MA_CHANNEL_LEFT; + pChannelMap[1] = MA_CHANNEL_RIGHT; + } break; + + case 3: + { + pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; + pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT; + pChannelMap[2] = MA_CHANNEL_BACK_CENTER; + } break; + + case 4: + { + pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; + pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT; + pChannelMap[2] = MA_CHANNEL_BACK_LEFT; + pChannelMap[3] = MA_CHANNEL_BACK_RIGHT; + } break; + + case 5: + { + pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; + pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT; + pChannelMap[2] = MA_CHANNEL_BACK_LEFT; + pChannelMap[3] = MA_CHANNEL_BACK_RIGHT; + pChannelMap[4] = MA_CHANNEL_FRONT_CENTER; + } break; + + case 6: + { + pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; + pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT; + pChannelMap[2] = MA_CHANNEL_BACK_LEFT; + pChannelMap[3] = MA_CHANNEL_BACK_RIGHT; + pChannelMap[4] = MA_CHANNEL_FRONT_CENTER; + pChannelMap[5] = MA_CHANNEL_LFE; + } break; + + case 7: + { + pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; + pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT; + pChannelMap[2] = MA_CHANNEL_BACK_LEFT; + pChannelMap[3] = MA_CHANNEL_BACK_RIGHT; + pChannelMap[4] = MA_CHANNEL_FRONT_CENTER; + pChannelMap[5] = MA_CHANNEL_BACK_CENTER; + pChannelMap[6] = MA_CHANNEL_LFE; + } break; + + case 8: + default: + { + pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; + pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT; + pChannelMap[2] = MA_CHANNEL_BACK_LEFT; + pChannelMap[3] = MA_CHANNEL_BACK_RIGHT; + pChannelMap[4] = MA_CHANNEL_FRONT_CENTER; + pChannelMap[5] = MA_CHANNEL_LFE; + pChannelMap[6] = MA_CHANNEL_SIDE_LEFT; + pChannelMap[7] = MA_CHANNEL_SIDE_RIGHT; } break; } @@ -34040,192 +34197,117 @@ static void ma_get_standard_channel_map_vorbis(ma_uint32 channels, ma_channel ch if (channels > 8) { ma_uint32 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_sound4(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) { case 1: { - channelMap[0] = MA_CHANNEL_MONO; + pChannelMap[0] = MA_CHANNEL_MONO; } break; case 2: { - channelMap[0] = MA_CHANNEL_LEFT; - channelMap[1] = MA_CHANNEL_RIGHT; + pChannelMap[0] = MA_CHANNEL_LEFT; + pChannelMap[1] = MA_CHANNEL_RIGHT; } break; case 3: { - channelMap[0] = MA_CHANNEL_FRONT_LEFT; - channelMap[1] = MA_CHANNEL_FRONT_RIGHT; - channelMap[2] = MA_CHANNEL_BACK_CENTER; + pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; + pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT; + pChannelMap[2] = MA_CHANNEL_FRONT_CENTER; } break; case 4: { - channelMap[0] = MA_CHANNEL_FRONT_LEFT; - channelMap[1] = MA_CHANNEL_FRONT_RIGHT; - channelMap[2] = MA_CHANNEL_BACK_LEFT; - channelMap[3] = MA_CHANNEL_BACK_RIGHT; + pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; + pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT; + pChannelMap[2] = MA_CHANNEL_BACK_LEFT; + pChannelMap[3] = MA_CHANNEL_BACK_RIGHT; } break; case 5: { - channelMap[0] = MA_CHANNEL_FRONT_LEFT; - channelMap[1] = MA_CHANNEL_FRONT_RIGHT; - channelMap[2] = MA_CHANNEL_BACK_LEFT; - channelMap[3] = MA_CHANNEL_BACK_RIGHT; - channelMap[4] = MA_CHANNEL_FRONT_CENTER; - } break; - - case 6: - { - channelMap[0] = MA_CHANNEL_FRONT_LEFT; - channelMap[1] = MA_CHANNEL_FRONT_RIGHT; - channelMap[2] = MA_CHANNEL_BACK_LEFT; - channelMap[3] = MA_CHANNEL_BACK_RIGHT; - channelMap[4] = MA_CHANNEL_FRONT_CENTER; - channelMap[5] = MA_CHANNEL_LFE; - } break; - - case 7: - { - channelMap[0] = MA_CHANNEL_FRONT_LEFT; - channelMap[1] = MA_CHANNEL_FRONT_RIGHT; - channelMap[2] = MA_CHANNEL_BACK_LEFT; - channelMap[3] = MA_CHANNEL_BACK_RIGHT; - channelMap[4] = MA_CHANNEL_FRONT_CENTER; - channelMap[5] = MA_CHANNEL_BACK_CENTER; - channelMap[6] = MA_CHANNEL_LFE; - } break; - - case 8: - default: - { - channelMap[0] = MA_CHANNEL_FRONT_LEFT; - channelMap[1] = MA_CHANNEL_FRONT_RIGHT; - channelMap[2] = MA_CHANNEL_BACK_LEFT; - channelMap[3] = MA_CHANNEL_BACK_RIGHT; - channelMap[4] = MA_CHANNEL_FRONT_CENTER; - channelMap[5] = MA_CHANNEL_LFE; - channelMap[6] = MA_CHANNEL_SIDE_LEFT; - channelMap[7] = MA_CHANNEL_SIDE_RIGHT; - } break; - } - - /* Remainder. */ - if (channels > 8) { - ma_uint32 iChannel; - for (iChannel = 8; iChannel < MA_MAX_CHANNELS; ++iChannel) { - channelMap[iChannel] = (ma_channel)(MA_CHANNEL_AUX_0 + (iChannel-8)); - } - } -} - -static void ma_get_standard_channel_map_sndio(ma_uint32 channels, ma_channel channelMap[MA_MAX_CHANNELS]) -{ - switch (channels) - { - case 1: - { - channelMap[0] = MA_CHANNEL_MONO; - } break; - - case 2: - { - channelMap[0] = MA_CHANNEL_LEFT; - channelMap[1] = MA_CHANNEL_RIGHT; - } break; - - case 3: - { - channelMap[0] = MA_CHANNEL_FRONT_LEFT; - channelMap[1] = MA_CHANNEL_FRONT_RIGHT; - channelMap[2] = MA_CHANNEL_FRONT_CENTER; - } break; - - case 4: - { - channelMap[0] = MA_CHANNEL_FRONT_LEFT; - channelMap[1] = MA_CHANNEL_FRONT_RIGHT; - channelMap[2] = MA_CHANNEL_BACK_LEFT; - channelMap[3] = MA_CHANNEL_BACK_RIGHT; - } break; - - case 5: - { - channelMap[0] = MA_CHANNEL_FRONT_LEFT; - channelMap[1] = MA_CHANNEL_FRONT_RIGHT; - channelMap[2] = MA_CHANNEL_BACK_LEFT; - channelMap[3] = MA_CHANNEL_BACK_RIGHT; - channelMap[4] = MA_CHANNEL_FRONT_CENTER; + pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; + pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT; + pChannelMap[2] = MA_CHANNEL_BACK_LEFT; + pChannelMap[3] = MA_CHANNEL_BACK_RIGHT; + pChannelMap[4] = MA_CHANNEL_FRONT_CENTER; } break; case 6: default: { - channelMap[0] = MA_CHANNEL_FRONT_LEFT; - channelMap[1] = MA_CHANNEL_FRONT_RIGHT; - channelMap[2] = MA_CHANNEL_BACK_LEFT; - channelMap[3] = MA_CHANNEL_BACK_RIGHT; - channelMap[4] = MA_CHANNEL_FRONT_CENTER; - channelMap[5] = MA_CHANNEL_LFE; + pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; + pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT; + pChannelMap[2] = MA_CHANNEL_BACK_LEFT; + pChannelMap[3] = MA_CHANNEL_BACK_RIGHT; + pChannelMap[4] = MA_CHANNEL_FRONT_CENTER; + pChannelMap[5] = MA_CHANNEL_LFE; } break; } /* Remainder. */ if (channels > 6) { ma_uint32 iChannel; - for (iChannel = 6; iChannel < MA_MAX_CHANNELS; ++iChannel) { - channelMap[iChannel] = (ma_channel)(MA_CHANNEL_AUX_0 + (iChannel-6)); + for (iChannel = 6; iChannel < channels && iChannel < MA_MAX_CHANNELS; ++iChannel) { + 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) { case ma_standard_channel_map_alsa: { - ma_get_standard_channel_map_alsa(channels, channelMap); + ma_get_standard_channel_map_alsa(channels, pChannelMap); } break; case ma_standard_channel_map_rfc3551: { - ma_get_standard_channel_map_rfc3551(channels, channelMap); + ma_get_standard_channel_map_rfc3551(channels, pChannelMap); } break; case ma_standard_channel_map_flac: { - ma_get_standard_channel_map_flac(channels, channelMap); + ma_get_standard_channel_map_flac(channels, pChannelMap); } break; case ma_standard_channel_map_vorbis: { - ma_get_standard_channel_map_vorbis(channels, channelMap); + ma_get_standard_channel_map_vorbis(channels, pChannelMap); } break; case ma_standard_channel_map_sound4: { - ma_get_standard_channel_map_sound4(channels, channelMap); + ma_get_standard_channel_map_sound4(channels, pChannelMap); } break; case ma_standard_channel_map_sndio: { - ma_get_standard_channel_map_sndio(channels, channelMap); + ma_get_standard_channel_map_sndio(channels, pChannelMap); } break; case ma_standard_channel_map_microsoft: default: { - ma_get_standard_channel_map_microsoft(channels, channelMap); + ma_get_standard_channel_map_microsoft(channels, pChannelMap); } break; } } @@ -34237,9 +34319,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; } @@ -34252,7 +34334,7 @@ MA_API ma_bool32 ma_channel_map_valid(ma_uint32 channels, const ma_channel chann if (channels > 1) { ma_uint32 iChannel; for (iChannel = 0; iChannel < channels; ++iChannel) { - if (channelMap[iChannel] == MA_CHANNEL_MONO) { + if (pChannelMap[iChannel] == MA_CHANNEL_MONO) { return MA_FALSE; } } @@ -34261,20 +34343,16 @@ MA_API ma_bool32 ma_channel_map_valid(ma_uint32 channels, const ma_channel chann 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; - if (channelMapA == channelMapB) { - return MA_FALSE; - } - - if (channels == 0 || channels > MA_MAX_CHANNELS) { - return MA_FALSE; + if (pChannelMapA == pChannelMapB) { + return MA_TRUE; } for (iChannel = 0; iChannel < channels; ++iChannel) { - if (channelMapA[iChannel] != channelMapB[iChannel]) { + if (pChannelMapA[iChannel] != pChannelMapB[iChannel]) { return MA_FALSE; } } @@ -34282,12 +34360,12 @@ MA_API ma_bool32 ma_channel_map_equal(ma_uint32 channels, const ma_channel chann 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; for (iChannel = 0; iChannel < channels; ++iChannel) { - if (channelMap[iChannel] != MA_CHANNEL_NONE) { + if (pChannelMap[iChannel] != MA_CHANNEL_NONE) { return MA_FALSE; } } @@ -34295,11 +34373,12 @@ MA_API ma_bool32 ma_channel_map_blank(ma_uint32 channels, const ma_channel chann 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; + for (iChannel = 0; iChannel < channels; ++iChannel) { - if (channelMap[iChannel] == channelPosition) { + if (pChannelMap[iChannel] == channelPosition) { return MA_TRUE; } } @@ -36836,7 +36915,7 @@ extern "C" { #define DRFLAC_XSTRINGIFY(x) DRFLAC_STRINGIFY(x) #define DRFLAC_VERSION_MAJOR 0 #define DRFLAC_VERSION_MINOR 12 -#define DRFLAC_VERSION_REVISION 14 +#define DRFLAC_VERSION_REVISION 15 #define DRFLAC_VERSION_STRING DRFLAC_XSTRINGIFY(DRFLAC_VERSION_MAJOR) "." DRFLAC_XSTRINGIFY(DRFLAC_VERSION_MINOR) "." DRFLAC_XSTRINGIFY(DRFLAC_VERSION_REVISION) #include #ifdef _MSC_VER @@ -37198,7 +37277,7 @@ extern "C" { #define DRMP3_XSTRINGIFY(x) DRMP3_STRINGIFY(x) #define DRMP3_VERSION_MAJOR 0 #define DRMP3_VERSION_MINOR 6 -#define DRMP3_VERSION_REVISION 12 +#define DRMP3_VERSION_REVISION 13 #define DRMP3_VERSION_STRING DRMP3_XSTRINGIFY(DRMP3_VERSION_MAJOR) "." DRMP3_XSTRINGIFY(DRMP3_VERSION_MINOR) "." DRMP3_XSTRINGIFY(DRMP3_VERSION_REVISION) #include #ifdef _MSC_VER @@ -37484,8 +37563,8 @@ MA_API ma_decoder_config ma_decoder_config_init(ma_format outputFormat, ma_uint3 { ma_decoder_config config; MA_ZERO_OBJECT(&config); - config.format = outputFormat; - config.channels = outputChannels; + config.format = outputFormat; + config.channels = ma_min(outputChannels, ma_countof(config.channelMap)); config.sampleRate = outputSampleRate; config.resampling.algorithm = ma_resample_algorithm_linear; config.resampling.linear.lpfOrder = ma_min(MA_DEFAULT_RESAMPLER_LPF_ORDER, MA_MAX_FILTER_ORDER); @@ -37513,6 +37592,18 @@ static ma_result ma_decoder__init_data_converter(ma_decoder* pDecoder, const ma_ ma_data_converter_config converterConfig; 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. */ if (pConfig->format == ma_format_unknown) { @@ -40542,6 +40633,10 @@ MA_API ma_result ma_noise_init(const ma_noise_config* pConfig, ma_noise* pNoise) 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.onSeek = ma_noise__data_source_on_seek; /* <-- No-op for noise. */ pNoise->ds.onGetDataFormat = ma_noise__data_source_on_get_data_format; @@ -47371,6 +47466,9 @@ static drflac_bool32 drflac__decode_samples__lpc(drflac_bs* bs, drflac_uint32 bl if (!drflac__read_int8(bs, 5, &lpcShift)) { return DRFLAC_FALSE; } + if (lpcShift < 0) { + return DRFLAC_FALSE; + } DRFLAC_ZERO_MEMORY(coefficients, sizeof(coefficients)); for (i = 0; i < lpcOrder; ++i) { if (!drflac__read_int32(bs, lpcPrecision, coefficients + i)) { @@ -55430,7 +55528,7 @@ DRMP3_API drmp3_uint64 drmp3_read_pcm_frames_f32(drmp3* pMP3, drmp3_uint64 frame if (framesJustRead == 0) { break; } - drmp3_s16_to_f32((float*)DRMP3_OFFSET_PTR(pBufferOut, sizeof(drmp3_int16) * totalPCMFramesRead * pMP3->channels), pTempS16, framesJustRead * pMP3->channels); + drmp3_s16_to_f32((float*)DRMP3_OFFSET_PTR(pBufferOut, sizeof(float) * totalPCMFramesRead * pMP3->channels), pTempS16, framesJustRead * pMP3->channels); totalPCMFramesRead += framesJustRead; } return totalPCMFramesRead; diff --git a/extras/miniaudio_split/miniaudio.h b/extras/miniaudio_split/miniaudio.h index d52e4d71..1ab6dce4 100644 --- a/extras/miniaudio_split/miniaudio.h +++ b/extras/miniaudio_split/miniaudio.h @@ -1,6 +1,6 @@ /* 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 - 2020-07-11 David Reid - davidreidsoftware@gmail.com @@ -19,7 +19,7 @@ extern "C" { #define MA_VERSION_MAJOR 0 #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) #if defined(_MSC_VER) && !defined(__clang__) @@ -488,6 +488,8 @@ typedef enum ma_thread_priority_default = 0 } ma_thread_priority; +typedef unsigned char ma_spinlock; + #if defined(MA_WIN32) typedef ma_handle ma_thread; #endif @@ -1077,7 +1079,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. */ } 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 { @@ -1210,11 +1212,15 @@ Channel Maps /* 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. + +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); @@ -1228,25 +1234,33 @@ is usually treated as a passthrough. Invalid channel maps: - A channel map with no channels - 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. 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). + +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. + +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); /************************************************************************************************************************************************************ @@ -3668,6 +3682,23 @@ MA_API ma_bool32 ma_is_loopback_supported(ma_backend backend); #ifndef MA_NO_THREADING + +/* +Locks a spinlock. +*/ +MA_API ma_result ma_spinlock_lock(ma_spinlock* pSpinlock); + +/* +Locks a spinlock, but does not yield() when looping. +*/ +MA_API ma_result ma_spinlock_lock_noyield(ma_spinlock* pSpinlock); + +/* +Unlocks a spinlock. +*/ +MA_API ma_result ma_spinlock_unlock(ma_spinlock* pSpinlock); + + /* Creates a mutex. diff --git a/miniaudio.h b/miniaudio.h index 285705dd..3a4e3ec7 100644 --- a/miniaudio.h +++ b/miniaudio.h @@ -1,6 +1,6 @@ /* Audio playback and capture library. Choice of public domain or MIT-0. See license statements at the end of this file. -miniaudio - v0.10.13 - TBD +miniaudio - v0.10.13 - 2020-07-11 David Reid - davidreidsoftware@gmail.com @@ -61964,7 +61964,7 @@ The following miscellaneous changes have also been made. /* REVISION HISTORY ================ -v0.10.13 - TBD +v0.10.13 - 2020-07-11 - Fix some potential buffer overflow errors with channel maps when channel counts are greater than MA_MAX_CHANNELS. - Fix compilation error on Emscripten. - Silence some unused function warnings.