From d5ba84605c1c17363c77fc87833409f287fffa66 Mon Sep 17 00:00:00 2001 From: David Reid Date: Fri, 26 Feb 2021 17:09:29 +1000 Subject: [PATCH 01/43] Fix a typo in the date for the previous version in revision history. --- miniaudio.h | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/miniaudio.h b/miniaudio.h index 053dfff3..37dbff7c 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.32 - 2020-02-23 +miniaudio - v0.10.33 - TBD David Reid - mackron@gmail.com @@ -1510,7 +1510,7 @@ extern "C" { #define MA_VERSION_MAJOR 0 #define MA_VERSION_MINOR 10 -#define MA_VERSION_REVISION 32 +#define MA_VERSION_REVISION 33 #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__) @@ -64470,7 +64470,10 @@ The following miscellaneous changes have also been made. /* REVISION HISTORY ================ -v0.10.32 - 2020-02-23 +v0.10.33 - TBD + - + +v0.10.32 - 2021-02-23 - WASAPI: Fix a deadlock in exclusive mode. - WASAPI: No longer return an error from ma_context_get_device_info() when an exclusive mode format cannot be retrieved. From 85cd9c1848f8d7ed8cd1c15930e900e08cf4bd19 Mon Sep 17 00:00:00 2001 From: David Reid Date: Sun, 28 Feb 2021 06:49:36 +1000 Subject: [PATCH 02/43] Fix a bug with ma_resource_manager_data_stream relating to seeking. --- research/miniaudio_engine.h | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/research/miniaudio_engine.h b/research/miniaudio_engine.h index 28735f72..c2559987 100644 --- a/research/miniaudio_engine.h +++ b/research/miniaudio_engine.h @@ -7268,6 +7268,16 @@ MA_API ma_result ma_resource_manager_data_stream_map(ma_resource_manager_data_st return MA_SUCCESS; } +static void ma_resource_manager_data_stream_set_absolute_cursor(ma_resource_manager_data_stream* pDataStream, ma_uint64 absoluteCursor) +{ + /* Loop if possible. */ + if (absoluteCursor > pDataStream->totalLengthInPCMFrames && pDataStream->totalLengthInPCMFrames > 0) { + absoluteCursor = absoluteCursor % pDataStream->totalLengthInPCMFrames; + } + + c89atomic_exchange_64(&pDataStream->absoluteCursor, absoluteCursor); +} + MA_API ma_result ma_resource_manager_data_stream_unmap(ma_resource_manager_data_stream* pDataStream, ma_uint64 frameCount) { ma_uint32 newRelativeCursor; @@ -7292,11 +7302,8 @@ MA_API ma_result ma_resource_manager_data_stream_unmap(ma_resource_manager_data_ pageSizeInFrames = ma_resource_manager_data_stream_get_page_size_in_frames(pDataStream); - /* The absolute cursor needs to be updated. We want to make sure to loop if possible. */ - pDataStream->absoluteCursor += frameCount; - if (pDataStream->absoluteCursor > pDataStream->totalLengthInPCMFrames && pDataStream->totalLengthInPCMFrames > 0) { - pDataStream->absoluteCursor = pDataStream->absoluteCursor % pDataStream->totalLengthInPCMFrames; - } + /* The absolute cursor needs to be updated for ma_resource_manager_data_stream_get_cursor_in_pcm_frames(). */ + ma_resource_manager_data_stream_set_absolute_cursor(pDataStream, c89atomic_load_64(&pDataStream->absoluteCursor) + frameCount); /* Here is where we need to check if we need to load a new page, and if so, post a job to load it. */ newRelativeCursor = pDataStream->relativeCursor + (ma_uint32)frameCount; @@ -7346,6 +7353,9 @@ MA_API ma_result ma_resource_manager_data_stream_seek_to_pcm_frame(ma_resource_m /* Increment the seek counter first to indicate to read_paged_pcm_frames() and map_paged_pcm_frames() that we are in the middle of a seek and MA_BUSY should be returned. */ c89atomic_fetch_add_32(&pDataStream->seekCounter, 1); + /* Update the absolute cursor so that ma_resource_manager_data_stream_get_cursor_in_pcm_frames() returns the new position. */ + ma_resource_manager_data_stream_set_absolute_cursor(pDataStream, frameIndex); + /* We need to clear our currently loaded pages so that the stream starts playback from the new seek point as soon as possible. These are for the purpose of the public API and will be ignored by the seek job. The seek job will operate on the assumption that both pages have been marked as invalid and the cursor is at the start of From c2c32ed1d71408dc082c41bf74e27a886f74e1ad Mon Sep 17 00:00:00 2001 From: David Reid Date: Mon, 1 Mar 2021 17:39:03 +1000 Subject: [PATCH 03/43] Fix a typo. --- miniaudio.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/miniaudio.h b/miniaudio.h index 37dbff7c..61bf605a 100644 --- a/miniaudio.h +++ b/miniaudio.h @@ -22892,7 +22892,7 @@ static ma_result ma_device_data_loop__pulse(ma_device* pDevice) /* NOTE: Don't start the device here. It'll be done at a higher level. */ /* - Are data is handled through callbacks. All we need to do is iterate over the main loop and let + All data is handled through callbacks. All we need to do is iterate over the main loop and let the callbacks deal with it. */ while (ma_device_get_state(pDevice) == MA_STATE_STARTED) { From 55e4e59bfa9b05d9fce126d10ffc8dda9d022b52 Mon Sep 17 00:00:00 2001 From: David Reid Date: Wed, 3 Mar 2021 17:29:46 +1000 Subject: [PATCH 04/43] Add support for configuring rolloff. --- research/miniaudio_engine.h | 60 +++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/research/miniaudio_engine.h b/research/miniaudio_engine.h index c2559987..8484ceb1 100644 --- a/research/miniaudio_engine.h +++ b/research/miniaudio_engine.h @@ -1586,6 +1586,8 @@ MA_API void ma_spatializer_set_attenuation_model(ma_spatializer* pSpatializer, m MA_API ma_attenuation_model ma_spatializer_get_attenuation_model(const ma_spatializer* pSpatializer); MA_API void ma_spatializer_set_positioning(ma_spatializer* pSpatializer, ma_positioning positioning); MA_API ma_positioning ma_spatializer_get_positioning(const ma_spatializer* pSpatializer); +MA_API void ma_spatializer_set_rolloff(ma_spatializer* pSpatializer, float rolloff); +MA_API float ma_spatializer_get_rolloff(const ma_spatializer* pSpatializer); MA_API void ma_spatializer_set_min_gain(ma_spatializer* pSpatializer, float minGain); MA_API float ma_spatializer_get_min_gain(const ma_spatializer* pSpatializer); MA_API void ma_spatializer_set_max_gain(ma_spatializer* pSpatializer, float maxGain); @@ -1781,6 +1783,8 @@ MA_API void ma_sound_set_attenuation_model(ma_sound* pSound, ma_attenuation_mode MA_API ma_attenuation_model ma_sound_get_attenuation_model(const ma_sound* pSound); MA_API void ma_sound_set_positioning(ma_sound* pSound, ma_positioning positioning); MA_API ma_positioning ma_sound_get_positioning(const ma_sound* pSound); +MA_API void ma_sound_set_rolloff(ma_sound* pSound, float rolloff); +MA_API float ma_sound_get_rolloff(const ma_sound* pSound); MA_API void ma_sound_set_min_gain(ma_sound* pSound, float minGain); MA_API float ma_sound_get_min_gain(const ma_sound* pSound); MA_API void ma_sound_set_max_gain(ma_sound* pSound, float maxGain); @@ -1832,6 +1836,8 @@ MA_API void ma_sound_group_set_attenuation_model(ma_sound_group* pGroup, ma_atte MA_API ma_attenuation_model ma_sound_group_get_attenuation_model(const ma_sound_group* pGroup); MA_API void ma_sound_group_set_positioning(ma_sound_group* pGroup, ma_positioning positioning); MA_API ma_positioning ma_sound_group_get_positioning(const ma_sound_group* pGroup); +MA_API void ma_sound_group_set_rolloff(ma_sound_group* pGroup, float rolloff); +MA_API float ma_sound_group_get_rolloff(const ma_sound_group* pGroup); MA_API void ma_sound_group_set_min_gain(ma_sound_group* pGroup, float minGain); MA_API float ma_sound_group_get_min_gain(const ma_sound_group* pGroup); MA_API void ma_sound_group_set_max_gain(ma_sound_group* pGroup, float maxGain); @@ -9670,6 +9676,24 @@ MA_API ma_positioning ma_spatializer_get_positioning(const ma_spatializer* pSpat return pSpatializer->config.positioning; } +MA_API void ma_spatializer_set_rolloff(ma_spatializer* pSpatializer, float rolloff) +{ + if (pSpatializer == NULL) { + return; + } + + pSpatializer->config.rolloff = rolloff; +} + +MA_API float ma_spatializer_get_rolloff(const ma_spatializer* pSpatializer) +{ + if (pSpatializer == NULL) { + return 0; + } + + return pSpatializer->config.rolloff; +} + MA_API void ma_spatializer_set_min_gain(ma_spatializer* pSpatializer, float minGain) { if (pSpatializer == NULL) { @@ -11305,6 +11329,24 @@ MA_API ma_positioning ma_sound_get_positioning(const ma_sound* pSound) return ma_spatializer_get_positioning(&pSound->engineNode.spatializer); } +MA_API void ma_sound_set_rolloff(ma_sound* pSound, float rolloff) +{ + if (pSound == NULL) { + return; + } + + ma_spatializer_set_rolloff(&pSound->engineNode.spatializer, rolloff); +} + +MA_API float ma_sound_get_rolloff(const ma_sound* pSound) +{ + if (pSound == NULL) { + return 0; + } + + return ma_spatializer_get_rolloff(&pSound->engineNode.spatializer); +} + MA_API void ma_sound_set_min_gain(ma_sound* pSound, float minGain) { if (pSound == NULL) { @@ -11853,6 +11895,24 @@ MA_API ma_positioning ma_sound_group_get_positioning(const ma_sound_group* pGrou return ma_spatializer_get_positioning(&pGroup->engineNode.spatializer); } +MA_API void ma_sound_group_set_rolloff(ma_sound_group* pGroup, float rolloff) +{ + if (pGroup == NULL) { + return; + } + + ma_spatializer_set_rolloff(&pGroup->engineNode.spatializer, rolloff); +} + +MA_API float ma_sound_group_get_rolloff(const ma_sound_group* pGroup) +{ + if (pGroup == NULL) { + return 0; + } + + return ma_spatializer_get_rolloff(&pGroup->engineNode.spatializer); +} + MA_API void ma_sound_group_set_min_gain(ma_sound_group* pGroup, float minGain) { if (pGroup == NULL) { From f8dd3780a2283eb4d40332c1e5de8432ca6bfd70 Mon Sep 17 00:00:00 2001 From: David Reid Date: Thu, 4 Mar 2021 17:12:58 +1000 Subject: [PATCH 05/43] Fix a typo. --- research/miniaudio_engine.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/research/miniaudio_engine.h b/research/miniaudio_engine.h index 8484ceb1..b337e5e4 100644 --- a/research/miniaudio_engine.h +++ b/research/miniaudio_engine.h @@ -1746,7 +1746,7 @@ MA_API ma_uint32 ma_engine_get_listener_count(const ma_engine* pEngine); MA_API ma_uint8 ma_engine_find_closest_listener(const ma_engine* pEngine, float absolutePosX, float absolutePosY, float absolutePosZ); MA_API void ma_engine_listener_set_position(ma_engine* pEngine, ma_uint32 listenerIndex, float x, float y, float z); MA_API ma_vec3f ma_engine_listener_get_position(const ma_engine* pEngine, ma_uint32 listenerIndex); -MA_API void ma_engine_listener_set_direciton(ma_engine* pEngine, ma_uint32 listenerIndex, float x, float y, float z); +MA_API void ma_engine_listener_set_direction(ma_engine* pEngine, ma_uint32 listenerIndex, float x, float y, float z); MA_API ma_vec3f ma_engine_listener_get_direction(const ma_engine* pEngine, ma_uint32 listenerIndex); MA_API void ma_engine_listener_set_velocity(ma_engine* pEngine, ma_uint32 listenerIndex, float x, float y, float z); MA_API ma_vec3f ma_engine_listener_get_velocity(const ma_engine* pEngine, ma_uint32 listenerIndex); @@ -10770,7 +10770,7 @@ MA_API ma_vec3f ma_engine_listener_get_position(const ma_engine* pEngine, ma_uin return ma_spatializer_listener_get_position(&pEngine->listeners[listenerIndex]); } -MA_API void ma_engine_listener_set_direciton(ma_engine* pEngine, ma_uint32 listenerIndex, float x, float y, float z) +MA_API void ma_engine_listener_set_direction(ma_engine* pEngine, ma_uint32 listenerIndex, float x, float y, float z) { if (pEngine == NULL || listenerIndex >= pEngine->listenerCount) { return; From a06ca7ee04088d715e898485ce44d30f5aff8213 Mon Sep 17 00:00:00 2001 From: David Reid Date: Thu, 4 Mar 2021 17:19:23 +1000 Subject: [PATCH 06/43] Prevent a division by zero. --- miniaudio.h | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/miniaudio.h b/miniaudio.h index 61bf605a..917e121e 100644 --- a/miniaudio.h +++ b/miniaudio.h @@ -33543,11 +33543,21 @@ MA_API ma_uint32 ma_scale_buffer_size(ma_uint32 baseBufferSize, float scale) MA_API ma_uint32 ma_calculate_buffer_size_in_milliseconds_from_frames(ma_uint32 bufferSizeInFrames, ma_uint32 sampleRate) { + /* Prevent a division by zero. */ + if (sampleRate == 0) { + return 0; + } + return bufferSizeInFrames / (sampleRate/1000); } MA_API ma_uint32 ma_calculate_buffer_size_in_frames_from_milliseconds(ma_uint32 bufferSizeInMilliseconds, ma_uint32 sampleRate) { + /* Prevent a division by zero. */ + if (sampleRate == 0) { + return 0; + } + return bufferSizeInMilliseconds * (sampleRate/1000); } @@ -64471,7 +64481,9 @@ The following miscellaneous changes have also been made. REVISION HISTORY ================ v0.10.33 - TBD - - + - Add a safety check to the following APIs to prevent a division by zero: + - ma_calculate_buffer_size_in_milliseconds_from_frames() + - ma_calculate_buffer_size_in_milliseconds_from_milliseconds() v0.10.32 - 2021-02-23 - WASAPI: Fix a deadlock in exclusive mode. From 062f150dc44e9a8568684be59b9e67bd5db99122 Mon Sep 17 00:00:00 2001 From: David Reid Date: Fri, 5 Mar 2021 17:39:46 +1000 Subject: [PATCH 07/43] Fix a typo. --- research/miniaudio_engine.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/research/miniaudio_engine.h b/research/miniaudio_engine.h index b337e5e4..cd58e0af 100644 --- a/research/miniaudio_engine.h +++ b/research/miniaudio_engine.h @@ -9754,7 +9754,7 @@ MA_API void ma_spatializer_set_max_distance(ma_spatializer* pSpatializer, float return; } - pSpatializer->config.minDistance = maxDistance; + pSpatializer->config.maxDistance = maxDistance; } MA_API float ma_spatializer_get_max_distance(const ma_spatializer* pSpatializer) From 22414f8c01b4bbefafe6c2c45ce722a68a04f039 Mon Sep 17 00:00:00 2001 From: Steven Noonan Date: Fri, 5 Mar 2021 09:15:13 -0800 Subject: [PATCH 08/43] miniaudio_engine: fix sample rate conversion for sounds Signed-off-by: Steven Noonan --- research/miniaudio_engine.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/research/miniaudio_engine.h b/research/miniaudio_engine.h index cd58e0af..cce6b9c8 100644 --- a/research/miniaudio_engine.h +++ b/research/miniaudio_engine.h @@ -1633,6 +1633,7 @@ typedef struct ma_engine* pEngine; ma_engine_node_type type; ma_uint32 channels; /* Only used when the type is set to ma_engine_node_type_sound. */ + ma_uint32 sampleRate; /* Only used when the type is set to ma_engine_node_type_sound. */ ma_bool8 isPitchDisabled; /* Pitching can be explicitly disable with MA_SOUND_FLAG_NO_PITCH to optimize processing. */ ma_bool8 isSpatializationDisabled; /* Spatialization can be explicitly disabled with MA_SOUND_FLAG_NO_SPATIALIZATION. */ ma_uint8 pinnedListenerIndex; /* The index of the listener this node should always use for spatialization. If set to (ma_uint8)-1 the engine will use the closest listener. */ @@ -10315,7 +10316,7 @@ MA_API ma_result ma_engine_node_init(const ma_engine_node_config* pConfig, const */ /* We'll always do resampling first. */ - resamplerConfig = ma_resampler_config_init(ma_format_f32, baseNodeConfig.inputChannels[0], ma_engine_get_sample_rate(pEngineNode->pEngine), ma_engine_get_sample_rate(pEngineNode->pEngine), ma_resample_algorithm_linear); + resamplerConfig = ma_resampler_config_init(ma_format_f32, baseNodeConfig.inputChannels[0], pConfig->sampleRate ? pConfig->sampleRate : ma_engine_get_sample_rate(pEngineNode->pEngine), ma_engine_get_sample_rate(pEngineNode->pEngine), ma_resample_algorithm_linear); resamplerConfig.linear.lpfOrder = 0; /* <-- Need to disable low-pass filtering for pitch shifting for now because there's cases where the biquads are becoming unstable. Need to figure out a better fix for this. */ result = ma_resampler_init(&resamplerConfig, &pEngineNode->resampler); @@ -10986,7 +10987,7 @@ static ma_result ma_sound_init_from_data_source_internal(ma_engine* pEngine, ma_ */ engineNodeConfig = ma_engine_node_config_init(pEngine, ma_engine_node_type_sound, flags); - result = ma_data_source_get_data_format(pDataSource, NULL, &engineNodeConfig.channels, NULL); + result = ma_data_source_get_data_format(pDataSource, NULL, &engineNodeConfig.channels, &engineNodeConfig.sampleRate); if (result != MA_SUCCESS) { return result; /* Failed to retrieve the channel count. */ } From 91b4b62bf57bc93f933027ef7e4d260565de517c Mon Sep 17 00:00:00 2001 From: David Reid Date: Sat, 6 Mar 2021 08:42:25 +1000 Subject: [PATCH 09/43] Minor clean up. --- research/miniaudio_engine.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/research/miniaudio_engine.h b/research/miniaudio_engine.h index cce6b9c8..f8146c57 100644 --- a/research/miniaudio_engine.h +++ b/research/miniaudio_engine.h @@ -10316,7 +10316,7 @@ MA_API ma_result ma_engine_node_init(const ma_engine_node_config* pConfig, const */ /* We'll always do resampling first. */ - resamplerConfig = ma_resampler_config_init(ma_format_f32, baseNodeConfig.inputChannels[0], pConfig->sampleRate ? pConfig->sampleRate : ma_engine_get_sample_rate(pEngineNode->pEngine), ma_engine_get_sample_rate(pEngineNode->pEngine), ma_resample_algorithm_linear); + resamplerConfig = ma_resampler_config_init(ma_format_f32, baseNodeConfig.inputChannels[0], (pConfig->sampleRate > 0) ? pConfig->sampleRate : ma_engine_get_sample_rate(pEngineNode->pEngine), ma_engine_get_sample_rate(pEngineNode->pEngine), ma_resample_algorithm_linear); resamplerConfig.linear.lpfOrder = 0; /* <-- Need to disable low-pass filtering for pitch shifting for now because there's cases where the biquads are becoming unstable. Need to figure out a better fix for this. */ result = ma_resampler_init(&resamplerConfig, &pEngineNode->resampler); From a5db7b6574d3f7953b18ee62464cffdff6f53309 Mon Sep 17 00:00:00 2001 From: Steven Noonan Date: Thu, 4 Mar 2021 09:04:02 -0800 Subject: [PATCH 10/43] resource manager: fix tree hierarchy when removing nodes Signed-off-by: Steven Noonan --- research/miniaudio_engine.h | 1 + 1 file changed, 1 insertion(+) diff --git a/research/miniaudio_engine.h b/research/miniaudio_engine.h index f8146c57..b84a9345 100644 --- a/research/miniaudio_engine.h +++ b/research/miniaudio_engine.h @@ -5443,6 +5443,7 @@ static ma_result ma_resource_manager_data_buffer_node_remove(ma_resource_manager pReplacementDataBufferNode->pParent->pChildHi = NULL; } } else { + pReplacementDataBufferNode->pChildHi->pParent = pReplacementDataBufferNode->pParent; if (pReplacementDataBufferNode->pParent->pChildLo == pReplacementDataBufferNode) { pReplacementDataBufferNode->pParent->pChildLo = pReplacementDataBufferNode->pChildHi; } else { From 61f5d4e0278ca21dd505d9bfaadcca14b82c0e21 Mon Sep 17 00:00:00 2001 From: David Reid Date: Sat, 6 Mar 2021 18:55:47 +1000 Subject: [PATCH 11/43] Fix a typo. --- research/miniaudio_engine.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/research/miniaudio_engine.h b/research/miniaudio_engine.h index b84a9345..b5a8fb5c 100644 --- a/research/miniaudio_engine.h +++ b/research/miniaudio_engine.h @@ -527,7 +527,7 @@ and include the following: | | `MA_NODE_FLAG_CONTINUOUS_PROCESSING`. When this | | | is set, the `ppFramesIn` parameter of the | | | processing callback will be set to NULL when | - | | there are no input frames are. available. When | + | | there are no input frames are available. When | | | this is unset, silence will be posted to the | | | processing callback. | +-----------------------------------------+---------------------------------------------------+ From 9c761921abb22ec043d4053b83b076c80dcd4dd0 Mon Sep 17 00:00:00 2001 From: David Reid Date: Tue, 9 Mar 2021 19:28:13 +1000 Subject: [PATCH 12/43] Try fixing an infinite loop. --- research/miniaudio_engine.h | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/research/miniaudio_engine.h b/research/miniaudio_engine.h index b5a8fb5c..112f8d57 100644 --- a/research/miniaudio_engine.h +++ b/research/miniaudio_engine.h @@ -9968,7 +9968,7 @@ static void ma_engine_node_process_pcm_frames__general(ma_engine_node* pEngineNo isPanningEnabled = pEngineNode->panner.pan != 0 && channelsOut != 1; /* Keep going while we've still got data available for processing. */ - while (totalFramesProcessedIn < frameCountIn && totalFramesProcessedOut < frameCountOut) { + while (totalFramesProcessedOut < frameCountOut) { /* We need to process in a specific order. We always do resampling first because it's likely we're going to be increasing the channel count after spatialization. Also, I want to do @@ -10082,9 +10082,14 @@ static void ma_engine_node_process_pcm_frames__general(ma_engine_node* pEngineNo ma_panner_process_pcm_frames(&pEngineNode->panner, pRunningFramesOut, pRunningFramesOut, framesJustProcessedOut); /* In-place processing. */ } - /* We're done. */ + /* We're done for this chunk. */ totalFramesProcessedIn += framesJustProcessedIn; totalFramesProcessedOut += framesJustProcessedOut; + + /* If we didn't process any output frames this iteration it means we've either run out of input data, or run out of room in the output buffer. */ + if (framesJustProcessedOut == 0) { + break; + } } /* At this point we're done processing. */ From 53eed5b5f21bda05b67549055f275f2245a6ade4 Mon Sep 17 00:00:00 2001 From: David Reid Date: Tue, 9 Mar 2021 20:51:31 +1000 Subject: [PATCH 13/43] Silence some -Wmaybe-uninitialized warnings. --- miniaudio.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/miniaudio.h b/miniaudio.h index 917e121e..fb666587 100644 --- a/miniaudio.h +++ b/miniaudio.h @@ -22511,9 +22511,9 @@ static ma_result ma_device_init__pulse(ma_device* pDevice, const ma_device_confi int error = 0; const char* devPlayback = NULL; const char* devCapture = NULL; - ma_format format; - ma_uint32 channels; - ma_uint32 sampleRate; + ma_format format = ma_format_unknown; + ma_uint32 channels = 0; + ma_uint32 sampleRate = 0; ma_pa_sink_info sinkInfo; ma_pa_source_info sourceInfo; ma_pa_sample_spec ss; From 6c4937f495f1a1389c6f12cee4545e004c535514 Mon Sep 17 00:00:00 2001 From: Steven Noonan Date: Tue, 9 Mar 2021 04:43:59 -0800 Subject: [PATCH 14/43] engine: use atomics for setting live pitch and spatialization variables Thread Sanitizer was unhappy about these variables being modified on one thread and read on another (data race). Signed-off-by: Steven Noonan --- research/miniaudio_engine.h | 42 +++++++++++++++++++------------------ 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/research/miniaudio_engine.h b/research/miniaudio_engine.h index 112f8d57..b3cd0469 100644 --- a/research/miniaudio_engine.h +++ b/research/miniaudio_engine.h @@ -1645,18 +1645,18 @@ MA_API ma_engine_node_config ma_engine_node_config_init(ma_engine* pEngine, ma_e /* Base node object for both ma_sound and ma_sound_group. */ typedef struct { - ma_node_base baseNode; /* Must be the first member for compatiblity with the ma_node API. */ - ma_engine* pEngine; /* A pointer to the engine. Set based on the value from the config. */ + ma_node_base baseNode; /* Must be the first member for compatiblity with the ma_node API. */ + ma_engine* pEngine; /* A pointer to the engine. Set based on the value from the config. */ ma_fader fader; - ma_resampler resampler; /* For pitch shift. May change this to ma_linear_resampler later. */ + ma_resampler resampler; /* For pitch shift. May change this to ma_linear_resampler later. */ ma_spatializer spatializer; ma_panner panner; - float pitch; - float oldPitch; /* For determining whether or not the resampler needs to be updated to reflect the new pitch. The resampler will be updated on the mixing thread. */ - float oldDopplerPitch; /* For determining whether or not the resampler needs to be updated to take a new doppler pitch into account. */ - ma_bool8 isPitchDisabled; /* When set to true, pitching will be disabled which will allow the resampler to be bypassed to save some computation. */ - ma_bool8 isSpatializationDisabled; /* Set to false by default. When set to false, will not have spatialisation applied. */ - ma_uint8 pinnedListenerIndex; /* The index of the listener this node should always use for spatialization. If set to (ma_uint8)-1 the engine will use the closest listener. */ + MA_ATOMIC float pitch; + float oldPitch; /* For determining whether or not the resampler needs to be updated to reflect the new pitch. The resampler will be updated on the mixing thread. */ + float oldDopplerPitch; /* For determining whether or not the resampler needs to be updated to take a new doppler pitch into account. */ + MA_ATOMIC ma_bool8 isPitchDisabled; /* When set to true, pitching will be disabled which will allow the resampler to be bypassed to save some computation. */ + MA_ATOMIC ma_bool8 isSpatializationDisabled; /* Set to false by default. When set to false, will not have spatialisation applied. */ + MA_ATOMIC ma_uint8 pinnedListenerIndex; /* The index of the listener this node should always use for spatialization. If set to (ma_uint8)-1 the engine will use the closest listener. */ } ma_engine_node; MA_API ma_result ma_engine_node_init(const ma_engine_node_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_engine_node* pEngineNode); @@ -9901,8 +9901,10 @@ static void ma_engine_node_update_pitch_if_required(ma_engine_node* pEngineNode) MA_ASSERT(pEngineNode != NULL); - if (pEngineNode->oldPitch != pEngineNode->pitch) { - pEngineNode->oldPitch = pEngineNode->pitch; + float newPitch = c89atomic_load_explicit_f32(&pEngineNode->pitch, c89atomic_memory_order_acquire); + + if (pEngineNode->oldPitch != newPitch) { + pEngineNode->oldPitch = newPitch; isUpdateRequired = MA_TRUE; } @@ -9921,14 +9923,14 @@ static ma_bool32 ma_engine_node_is_pitching_enabled(const ma_engine_node* pEngin MA_ASSERT(pEngineNode != NULL); /* Don't try to be clever by skiping resampling in the pitch=1 case or else you'll glitch when moving away from 1. */ - return !pEngineNode->isPitchDisabled; + return !c89atomic_load_explicit_8(&pEngineNode->isPitchDisabled, c89atomic_memory_order_acquire); } static ma_bool32 ma_engine_node_is_spatialization_enabled(const ma_engine_node* pEngineNode) { MA_ASSERT(pEngineNode != NULL); - return !pEngineNode->isSpatializationDisabled; + return !c89atomic_load_explicit_8(&pEngineNode->isSpatializationDisabled, c89atomic_memory_order_acquire); } static ma_uint64 ma_engine_node_get_required_input_frame_count(const ma_engine_node* pEngineNode, ma_uint64 outputFrameCount) @@ -11196,7 +11198,7 @@ MA_API ma_result ma_sound_set_pitch(ma_sound* pSound, float pitch) return MA_INVALID_ARGS; } - pSound->engineNode.pitch = pitch; + c89atomic_exchange_explicit_f32(&pSound->engineNode.pitch, pitch, c89atomic_memory_order_release); return MA_SUCCESS; } @@ -11225,7 +11227,7 @@ MA_API void ma_sound_set_spatialization_enabled(ma_sound* pSound, ma_bool32 enab return; } - pSound->engineNode.isSpatializationDisabled = !enabled; + c89atomic_exchange_explicit_8(&pSound->engineNode.isSpatializationDisabled, !enabled, c89atomic_memory_order_release); } MA_API void ma_sound_set_pinned_listener_index(ma_sound* pSound, ma_uint8 listenerIndex) @@ -11234,7 +11236,7 @@ MA_API void ma_sound_set_pinned_listener_index(ma_sound* pSound, ma_uint8 listen return; } - pSound->engineNode.pinnedListenerIndex = listenerIndex; + c89atomic_exchange_explicit_8(&pSound->engineNode.pinnedListenerIndex, listenerIndex, c89atomic_memory_order_release); } MA_API ma_uint8 ma_sound_get_pinned_listener_index(const ma_sound* pSound) @@ -11243,7 +11245,7 @@ MA_API ma_uint8 ma_sound_get_pinned_listener_index(const ma_sound* pSound) return (ma_uint8)-1; } - return pSound->engineNode.pinnedListenerIndex; + return c89atomic_load_explicit_8(&pSound->engineNode.pinnedListenerIndex, c89atomic_memory_order_acquire); } MA_API void ma_sound_set_position(ma_sound* pSound, float x, float y, float z) @@ -11791,7 +11793,7 @@ MA_API void ma_sound_group_set_spatialization_enabled(ma_sound_group* pGroup, ma return; } - pGroup->engineNode.isSpatializationDisabled = !enabled; + c89atomic_exchange_explicit_8(&pGroup->engineNode.isSpatializationDisabled, !enabled, c89atomic_memory_order_release); } MA_API void ma_sound_group_set_pinned_listener_index(ma_sound_group* pGroup, ma_uint8 listenerIndex) @@ -11800,7 +11802,7 @@ MA_API void ma_sound_group_set_pinned_listener_index(ma_sound_group* pGroup, ma_ return; } - pGroup->engineNode.pinnedListenerIndex = listenerIndex; + c89atomic_exchange_explicit_8(&pGroup->engineNode.pinnedListenerIndex, listenerIndex, c89atomic_memory_order_release); } MA_API ma_uint8 ma_sound_group_get_pinned_listener_index(const ma_sound_group* pGroup) @@ -11809,7 +11811,7 @@ MA_API ma_uint8 ma_sound_group_get_pinned_listener_index(const ma_sound_group* p return (ma_uint8)-1; } - return pGroup->engineNode.pinnedListenerIndex; + return c89atomic_load_explicit_8(&pGroup->engineNode.pinnedListenerIndex, c89atomic_memory_order_acquire); } MA_API void ma_sound_group_set_position(ma_sound_group* pGroup, float x, float y, float z) From 7a1cc44170cd36d1163a832c7d6b19c02c0d6b11 Mon Sep 17 00:00:00 2001 From: Steven Noonan Date: Tue, 9 Mar 2021 10:52:09 -0800 Subject: [PATCH 15/43] atomics: use "const" pointers for the load-only atomics on MSVC Signed-off-by: Steven Noonan --- miniaudio.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/miniaudio.h b/miniaudio.h index fb666587..d7a04c49 100644 --- a/miniaudio.h +++ b/miniaudio.h @@ -8720,28 +8720,28 @@ typedef unsigned char c89atomic_bool; #define c89atomic_compiler_fence() c89atomic_thread_fence(c89atomic_memory_order_seq_cst) #define c89atomic_signal_fence(order) c89atomic_thread_fence(order) #if defined(C89ATOMIC_HAS_8) - static C89ATOMIC_INLINE c89atomic_uint8 c89atomic_load_explicit_8(volatile c89atomic_uint8* ptr, c89atomic_memory_order order) + static C89ATOMIC_INLINE c89atomic_uint8 c89atomic_load_explicit_8(volatile const c89atomic_uint8* ptr, c89atomic_memory_order order) { (void)order; return c89atomic_compare_and_swap_8(ptr, 0, 0); } #endif #if defined(C89ATOMIC_HAS_16) - static C89ATOMIC_INLINE c89atomic_uint16 c89atomic_load_explicit_16(volatile c89atomic_uint16* ptr, c89atomic_memory_order order) + static C89ATOMIC_INLINE c89atomic_uint16 c89atomic_load_explicit_16(volatile const c89atomic_uint16* ptr, c89atomic_memory_order order) { (void)order; return c89atomic_compare_and_swap_16(ptr, 0, 0); } #endif #if defined(C89ATOMIC_HAS_32) - static C89ATOMIC_INLINE c89atomic_uint32 c89atomic_load_explicit_32(volatile c89atomic_uint32* ptr, c89atomic_memory_order order) + static C89ATOMIC_INLINE c89atomic_uint32 c89atomic_load_explicit_32(volatile const c89atomic_uint32* ptr, c89atomic_memory_order order) { (void)order; return c89atomic_compare_and_swap_32(ptr, 0, 0); } #endif #if defined(C89ATOMIC_HAS_64) - static C89ATOMIC_INLINE c89atomic_uint64 c89atomic_load_explicit_64(volatile c89atomic_uint64* ptr, c89atomic_memory_order order) + static C89ATOMIC_INLINE c89atomic_uint64 c89atomic_load_explicit_64(volatile const c89atomic_uint64* ptr, c89atomic_memory_order order) { (void)order; return c89atomic_compare_and_swap_64(ptr, 0, 0); From 6f22b36eb71d8d52c18d47be8e8157896a4aa029 Mon Sep 17 00:00:00 2001 From: "morlad (iLeitgeb)" Date: Wed, 10 Mar 2021 06:16:21 +0000 Subject: [PATCH 16/43] Fix memory leak (macOS) --- miniaudio.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/miniaudio.h b/miniaudio.h index fb666587..28cd9352 100644 --- a/miniaudio.h +++ b/miniaudio.h @@ -25224,6 +25224,8 @@ static ma_result ma_context_get_device_info__coreaudio(ma_context* pContext, ma_ } } + ma_free(pSampleRateRanges, &pContext->allocationCallbacks); + if (pDeviceInfo->nativeDataFormatCount >= ma_countof(pDeviceInfo->nativeDataFormats)) { break; /* No more room for any more formats. */ } From eadd71739718de8273488395ed9751a4bf81b3b2 Mon Sep 17 00:00:00 2001 From: "morlad (iLeitgeb)" Date: Wed, 10 Mar 2021 06:42:46 +0000 Subject: [PATCH 17/43] Fix -Wcast-qual by using correct ma_offset_pcm_frames_ptr() --- miniaudio.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/miniaudio.h b/miniaudio.h index fb666587..09ba639d 100644 --- a/miniaudio.h +++ b/miniaudio.h @@ -5820,7 +5820,7 @@ Offsets a pointer by the specified number of PCM frames. */ MA_API void* ma_offset_pcm_frames_ptr(void* p, ma_uint64 offsetInFrames, ma_format format, ma_uint32 channels); MA_API const void* ma_offset_pcm_frames_const_ptr(const void* p, ma_uint64 offsetInFrames, ma_format format, ma_uint32 channels); -static MA_INLINE float* ma_offset_pcm_frames_ptr_f32(float* p, ma_uint64 offsetInFrames, ma_uint32 channels) { return (float*)ma_offset_pcm_frames_const_ptr((void*)p, offsetInFrames, ma_format_f32, channels); } +static MA_INLINE float* ma_offset_pcm_frames_ptr_f32(float* p, ma_uint64 offsetInFrames, ma_uint32 channels) { return (float*)ma_offset_pcm_frames_ptr((void*)p, offsetInFrames, ma_format_f32, channels); } static MA_INLINE const float* ma_offset_pcm_frames_const_ptr_f32(const float* p, ma_uint64 offsetInFrames, ma_uint32 channels) { return (const float*)ma_offset_pcm_frames_const_ptr((const void*)p, offsetInFrames, ma_format_f32, channels); } From 3a31faf8f02c7d67a93fe0663819bbb4c75d6c8a Mon Sep 17 00:00:00 2001 From: "morlad (iLeitgeb)" Date: Wed, 17 Feb 2021 08:31:42 +0000 Subject: [PATCH 18/43] Fix linker error when MA_NO_RESOURCE_MANAGER is defined --- research/miniaudio_engine.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/research/miniaudio_engine.h b/research/miniaudio_engine.h index 112f8d57..e1529399 100644 --- a/research/miniaudio_engine.h +++ b/research/miniaudio_engine.h @@ -10840,6 +10840,7 @@ MA_API void ma_engine_listener_get_cone(const ma_engine* pEngine, ma_uint32 list } +#ifndef MA_NO_RESOURCE_MANAGER MA_API ma_result ma_engine_play_sound_ex(ma_engine* pEngine, const char* pFilePath, ma_node* pNode, ma_uint32 nodeInputBusIndex) { ma_result result = MA_SUCCESS; @@ -10954,6 +10955,7 @@ MA_API ma_result ma_engine_play_sound(ma_engine* pEngine, const char* pFilePath, { return ma_engine_play_sound_ex(pEngine, pFilePath, pGroup, 0); } +#endif static ma_result ma_sound_preinit(ma_engine* pEngine, ma_sound* pSound) From c2fd23c983599109a45bd7deda3414fcb3988b89 Mon Sep 17 00:00:00 2001 From: "morlad (iLeitgeb)" Date: Tue, 16 Feb 2021 12:24:02 +0000 Subject: [PATCH 19/43] Fix CoreAudio's performanceProfile for playback not being set --- miniaudio.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/miniaudio.h b/miniaudio.h index fb666587..b1798ed4 100644 --- a/miniaudio.h +++ b/miniaudio.h @@ -26653,7 +26653,7 @@ static ma_result ma_device_init__coreaudio(ma_device* pDevice, const ma_device_c data.sampleRateIn = pDescriptorPlayback->sampleRate; MA_COPY_MEMORY(data.channelMapIn, pDescriptorPlayback->channelMap, sizeof(pDescriptorPlayback->channelMap)); data.shareMode = pDescriptorPlayback->shareMode; - data.shareMode = pDescriptorPlayback->shareMode; + data.performanceProfile = pConfig->performanceProfile; /* In full-duplex mode we want the playback buffer to be the same size as the capture buffer. */ if (pConfig->deviceType == ma_device_type_duplex) { From c12730bcabe3edf56c1a4688934b17668a77a76d Mon Sep 17 00:00:00 2001 From: David Reid Date: Wed, 10 Mar 2021 17:23:38 +1000 Subject: [PATCH 20/43] Update c89atomic. --- miniaudio.h | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/miniaudio.h b/miniaudio.h index fb666587..348d0c68 100644 --- a/miniaudio.h +++ b/miniaudio.h @@ -8720,28 +8720,28 @@ typedef unsigned char c89atomic_bool; #define c89atomic_compiler_fence() c89atomic_thread_fence(c89atomic_memory_order_seq_cst) #define c89atomic_signal_fence(order) c89atomic_thread_fence(order) #if defined(C89ATOMIC_HAS_8) - static C89ATOMIC_INLINE c89atomic_uint8 c89atomic_load_explicit_8(volatile c89atomic_uint8* ptr, c89atomic_memory_order order) + static C89ATOMIC_INLINE c89atomic_uint8 c89atomic_load_explicit_8(volatile const c89atomic_uint8* ptr, c89atomic_memory_order order) { (void)order; return c89atomic_compare_and_swap_8(ptr, 0, 0); } #endif #if defined(C89ATOMIC_HAS_16) - static C89ATOMIC_INLINE c89atomic_uint16 c89atomic_load_explicit_16(volatile c89atomic_uint16* ptr, c89atomic_memory_order order) + static C89ATOMIC_INLINE c89atomic_uint16 c89atomic_load_explicit_16(volatile const c89atomic_uint16* ptr, c89atomic_memory_order order) { (void)order; return c89atomic_compare_and_swap_16(ptr, 0, 0); } #endif #if defined(C89ATOMIC_HAS_32) - static C89ATOMIC_INLINE c89atomic_uint32 c89atomic_load_explicit_32(volatile c89atomic_uint32* ptr, c89atomic_memory_order order) + static C89ATOMIC_INLINE c89atomic_uint32 c89atomic_load_explicit_32(volatile const c89atomic_uint32* ptr, c89atomic_memory_order order) { (void)order; return c89atomic_compare_and_swap_32(ptr, 0, 0); } #endif #if defined(C89ATOMIC_HAS_64) - static C89ATOMIC_INLINE c89atomic_uint64 c89atomic_load_explicit_64(volatile c89atomic_uint64* ptr, c89atomic_memory_order order) + static C89ATOMIC_INLINE c89atomic_uint64 c89atomic_load_explicit_64(volatile const c89atomic_uint64* ptr, c89atomic_memory_order order) { (void)order; return c89atomic_compare_and_swap_64(ptr, 0, 0); @@ -9552,25 +9552,25 @@ typedef unsigned char c89atomic_bool; } #endif #define c89atomic_signal_fence(order) c89atomic_thread_fence(order) - static C89ATOMIC_INLINE c89atomic_uint8 c89atomic_load_explicit_8(volatile c89atomic_uint8* ptr, c89atomic_memory_order order) + static C89ATOMIC_INLINE c89atomic_uint8 c89atomic_load_explicit_8(volatile const c89atomic_uint8* ptr, c89atomic_memory_order order) { (void)order; - return c89atomic_compare_and_swap_8(ptr, 0, 0); + return c89atomic_compare_and_swap_8((c89atomic_uint8*)ptr, 0, 0); } - static C89ATOMIC_INLINE c89atomic_uint16 c89atomic_load_explicit_16(volatile c89atomic_uint16* ptr, c89atomic_memory_order order) + static C89ATOMIC_INLINE c89atomic_uint16 c89atomic_load_explicit_16(volatile const c89atomic_uint16* ptr, c89atomic_memory_order order) { (void)order; - return c89atomic_compare_and_swap_16(ptr, 0, 0); + return c89atomic_compare_and_swap_16((c89atomic_uint16*)ptr, 0, 0); } - static C89ATOMIC_INLINE c89atomic_uint32 c89atomic_load_explicit_32(volatile c89atomic_uint32* ptr, c89atomic_memory_order order) + static C89ATOMIC_INLINE c89atomic_uint32 c89atomic_load_explicit_32(volatile const c89atomic_uint32* ptr, c89atomic_memory_order order) { (void)order; - return c89atomic_compare_and_swap_32(ptr, 0, 0); + return c89atomic_compare_and_swap_32((c89atomic_uint32*)ptr, 0, 0); } - static C89ATOMIC_INLINE c89atomic_uint64 c89atomic_load_explicit_64(volatile c89atomic_uint64* ptr, c89atomic_memory_order order) + static C89ATOMIC_INLINE c89atomic_uint64 c89atomic_load_explicit_64(volatile const c89atomic_uint64* ptr, c89atomic_memory_order order) { (void)order; - return c89atomic_compare_and_swap_64(ptr, 0, 0); + return c89atomic_compare_and_swap_64((c89atomic_uint64*)ptr, 0, 0); } #define c89atomic_store_explicit_8( dst, src, order) (void)c89atomic_exchange_explicit_8 (dst, src, order) #define c89atomic_store_explicit_16(dst, src, order) (void)c89atomic_exchange_explicit_16(dst, src, order) From ecffc00ccf5e2531dfeebff6c32e2939e26788fe Mon Sep 17 00:00:00 2001 From: David Reid Date: Wed, 10 Mar 2021 17:31:42 +1000 Subject: [PATCH 21/43] Update revision history. --- miniaudio.h | 1 + 1 file changed, 1 insertion(+) diff --git a/miniaudio.h b/miniaudio.h index 348d0c68..2264fe06 100644 --- a/miniaudio.h +++ b/miniaudio.h @@ -64481,6 +64481,7 @@ The following miscellaneous changes have also been made. REVISION HISTORY ================ v0.10.33 - TBD + - Core Audio: Fix a memory leak. - Add a safety check to the following APIs to prevent a division by zero: - ma_calculate_buffer_size_in_milliseconds_from_frames() - ma_calculate_buffer_size_in_milliseconds_from_milliseconds() From feae709042ed6bd8532869e272beaae2d8e912b3 Mon Sep 17 00:00:00 2001 From: David Reid Date: Wed, 10 Mar 2021 17:34:41 +1000 Subject: [PATCH 22/43] Update revision history. --- miniaudio.h | 1 + 1 file changed, 1 insertion(+) diff --git a/miniaudio.h b/miniaudio.h index 66ca39c6..b8094772 100644 --- a/miniaudio.h +++ b/miniaudio.h @@ -64484,6 +64484,7 @@ REVISION HISTORY ================ v0.10.33 - TBD - Core Audio: Fix a memory leak. + - Core Audio: Fix a bug where the performance profile is not being used by playback devices. - Add a safety check to the following APIs to prevent a division by zero: - ma_calculate_buffer_size_in_milliseconds_from_frames() - ma_calculate_buffer_size_in_milliseconds_from_milliseconds() From e4ff49d5580823e6317b233eae752f0024bd57e5 Mon Sep 17 00:00:00 2001 From: Steven Noonan Date: Wed, 10 Mar 2021 07:43:54 -0800 Subject: [PATCH 23/43] wasapi: ensure that wasapi context structure is zeroed before filling it I had a situation where I was doing: ma_backend backends[] = { ma_backend_jack, ma_backend_wasapi, }; ma_context_init(backends, sizeof(backends)/sizeof(backends[0]), &contextConfig, &context); And since JACK was unavailable, it fell back to WASAPI. When this happened, the WASAPI commandIndex and commandCount variables were already stomped on by the JACK backend initialization, but the WASAPI backend assumes they are zero-initialized. Signed-off-by: Steven Noonan --- miniaudio.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/miniaudio.h b/miniaudio.h index d7b5c113..5166f93f 100644 --- a/miniaudio.h +++ b/miniaudio.h @@ -16257,6 +16257,8 @@ static ma_result ma_context_init__wasapi(ma_context* pContext, const ma_context_ return result; } + MA_ZERO_OBJECT(&pContext->wasapi); + /* Annoyingly, WASAPI does not allow you to release an IAudioClient object from a different thread than the one that retrieved it with GetService(). This can result in a deadlock in two From c9e2258daedef338e10fdd3c88287de533b4d3cd Mon Sep 17 00:00:00 2001 From: Steven Noonan Date: Sat, 13 Mar 2021 17:46:22 -0800 Subject: [PATCH 24/43] introduce MA_COMPILER_HAS_BUILTIN macro Both GCC and Clang can use this feature, so let's make it more general. I didn't touch the dr_wav/dr_flac parts using this, since I figure the amalgamated miniaudio.h header isn't the primary source for those. Signed-off-by: Steven Noonan --- miniaudio.h | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/miniaudio.h b/miniaudio.h index 5166f93f..e22f4b1f 100644 --- a/miniaudio.h +++ b/miniaudio.h @@ -6734,22 +6734,25 @@ static MA_INLINE ma_bool32 ma_has_neon(void) #endif #endif +#if defined(__has_builtin) + #define MA_COMPILER_HAS_BUILTIN(x) __has_builtin(x) +#else + #define MA_COMPILER_HAS_BUILTIN(x) 0 +#endif #if defined(_MSC_VER) && _MSC_VER >= 1400 #define MA_HAS_BYTESWAP16_INTRINSIC #define MA_HAS_BYTESWAP32_INTRINSIC #define MA_HAS_BYTESWAP64_INTRINSIC #elif defined(__clang__) - #if defined(__has_builtin) - #if __has_builtin(__builtin_bswap16) - #define MA_HAS_BYTESWAP16_INTRINSIC - #endif - #if __has_builtin(__builtin_bswap32) - #define MA_HAS_BYTESWAP32_INTRINSIC - #endif - #if __has_builtin(__builtin_bswap64) - #define MA_HAS_BYTESWAP64_INTRINSIC - #endif + #if MA_COMPILER_HAS_BUILTIN(__builtin_bswap16) + #define MA_HAS_BYTESWAP16_INTRINSIC + #endif + #if MA_COMPILER_HAS_BUILTIN(__builtin_bswap32) + #define MA_HAS_BYTESWAP32_INTRINSIC + #endif + #if MA_COMPILER_HAS_BUILTIN(__builtin_bswap64) + #define MA_HAS_BYTESWAP64_INTRINSIC #endif #elif defined(__GNUC__) #if ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)) From 5472d8418065bfd3a6e1ce3cd0afa6b60c11eb6e Mon Sep 17 00:00:00 2001 From: Steven Noonan Date: Sat, 13 Mar 2021 17:48:41 -0800 Subject: [PATCH 25/43] introduce MA_ASSUME macro This macro can be used to tell the compiler's optimization passes static assumptions which you *know* are true about code behavior. Use of these can be risky -- if you assume incorrectly, the compiler may emit code that will not work in circumstances you didn't anticipate. On the other hand, use of this macro in places where the optimizer is missing an assumption that would have been safe to make can cause it to emit more compact/optimal code. Signed-off-by: Steven Noonan --- miniaudio.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/miniaudio.h b/miniaudio.h index e22f4b1f..6d648d61 100644 --- a/miniaudio.h +++ b/miniaudio.h @@ -6740,6 +6740,18 @@ static MA_INLINE ma_bool32 ma_has_neon(void) #define MA_COMPILER_HAS_BUILTIN(x) 0 #endif +#ifndef MA_ASSUME + #if MA_COMPILER_HAS_BUILTIN(__builtin_assume) + #define MA_ASSUME(x) __builtin_assume(x) + #elif MA_COMPILER_HAS_BUILTIN(__builtin_unreachable) + #define MA_ASSUME(x) do { if (!(x)) __builtin_unreachable(); } while (0) + #elif defined(_MSC_VER) + #define MA_ASSUME(x) __assume(x) + #else + #define MA_ASSUME(x) while(0) + #endif +#endif + #if defined(_MSC_VER) && _MSC_VER >= 1400 #define MA_HAS_BYTESWAP16_INTRINSIC #define MA_HAS_BYTESWAP32_INTRINSIC From 2dcce6d53bfc6708a57b36ab272dcd36526ee9ec Mon Sep 17 00:00:00 2001 From: Steven Noonan Date: Sat, 13 Mar 2021 19:09:55 -0800 Subject: [PATCH 26/43] introduce MA_RESTRICT macro This allows us to use the __restrict keyword in places where we know that pointers do not alias. Signed-off-by: Steven Noonan --- miniaudio.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/miniaudio.h b/miniaudio.h index 6d648d61..728da361 100644 --- a/miniaudio.h +++ b/miniaudio.h @@ -6752,6 +6752,14 @@ static MA_INLINE ma_bool32 ma_has_neon(void) #endif #endif +#ifndef MA_RESTRICT + #if defined(__clang__) || defined(__GNUC__) || defined(_MSC_VER) + #define MA_RESTRICT __restrict + #else + #define MA_RESTRICT + #endif +#endif + #if defined(_MSC_VER) && _MSC_VER >= 1400 #define MA_HAS_BYTESWAP16_INTRINSIC #define MA_HAS_BYTESWAP32_INTRINSIC From c88bb8ccd2574bab5036b2d529106c00fef66fae Mon Sep 17 00:00:00 2001 From: Steven Noonan Date: Mon, 15 Mar 2021 04:08:34 -0700 Subject: [PATCH 27/43] extract channel count constants from loops These values are constant, but Clang has some trouble noticing that, especially if the loop body is complex enough. This prevents it from noticing places where vectorization is possible (and desirable). Signed-off-by: Steven Noonan --- miniaudio.h | 99 ++++++++++++++++++++----------------- research/miniaudio_engine.h | 10 ++-- 2 files changed, 61 insertions(+), 48 deletions(-) diff --git a/miniaudio.h b/miniaudio.h index 728da361..03ebc713 100644 --- a/miniaudio.h +++ b/miniaudio.h @@ -36317,13 +36317,14 @@ MA_API ma_result ma_biquad_reinit(const ma_biquad_config* pConfig, ma_biquad* pB static MA_INLINE void ma_biquad_process_pcm_frame_f32__direct_form_2_transposed(ma_biquad* pBQ, float* pY, const float* pX) { ma_uint32 c; + const ma_uint32 channels = pBQ->channels; const float b0 = pBQ->b0.f32; const float b1 = pBQ->b1.f32; const float b2 = pBQ->b2.f32; const float a1 = pBQ->a1.f32; const float a2 = pBQ->a2.f32; - for (c = 0; c < pBQ->channels; c += 1) { + for (c = 0; c < channels; c += 1) { float r1 = pBQ->r1[c].f32; float r2 = pBQ->r2[c].f32; float x = pX[c]; @@ -36347,13 +36348,14 @@ static MA_INLINE void ma_biquad_process_pcm_frame_f32(ma_biquad* pBQ, float* pY, static MA_INLINE void ma_biquad_process_pcm_frame_s16__direct_form_2_transposed(ma_biquad* pBQ, ma_int16* pY, const ma_int16* pX) { ma_uint32 c; + const ma_uint32 channels = pBQ->channels; const ma_int32 b0 = pBQ->b0.s32; const ma_int32 b1 = pBQ->b1.s32; const ma_int32 b2 = pBQ->b2.s32; const ma_int32 a1 = pBQ->a1.s32; const ma_int32 a2 = pBQ->a2.s32; - for (c = 0; c < pBQ->channels; c += 1) { + for (c = 0; c < channels; c += 1) { ma_int32 r1 = pBQ->r1[c].s32; ma_int32 r2 = pBQ->r2[c].s32; ma_int32 x = pX[c]; @@ -36517,10 +36519,11 @@ MA_API ma_result ma_lpf1_reinit(const ma_lpf1_config* pConfig, ma_lpf1* pLPF) static MA_INLINE void ma_lpf1_process_pcm_frame_f32(ma_lpf1* pLPF, float* pY, const float* pX) { ma_uint32 c; + const ma_uint32 channels = pLPF->channels; const float a = pLPF->a.f32; const float b = 1 - a; - for (c = 0; c < pLPF->channels; c += 1) { + for (c = 0; c < channels; c += 1) { float r1 = pLPF->r1[c].f32; float x = pX[c]; float y; @@ -36535,10 +36538,11 @@ static MA_INLINE void ma_lpf1_process_pcm_frame_f32(ma_lpf1* pLPF, float* pY, co static MA_INLINE void ma_lpf1_process_pcm_frame_s16(ma_lpf1* pLPF, ma_int16* pY, const ma_int16* pX) { ma_uint32 c; + const ma_uint32 channels = pLPF->channels; const ma_int32 a = pLPF->a.s32; const ma_int32 b = ((1 << MA_BIQUAD_FIXED_POINT_SHIFT) - a); - for (c = 0; c < pLPF->channels; c += 1) { + for (c = 0; c < channels; c += 1) { ma_int32 r1 = pLPF->r1[c].s32; ma_int32 x = pX[c]; ma_int32 y; @@ -37024,10 +37028,11 @@ MA_API ma_result ma_hpf1_reinit(const ma_hpf1_config* pConfig, ma_hpf1* pHPF) static MA_INLINE void ma_hpf1_process_pcm_frame_f32(ma_hpf1* pHPF, float* pY, const float* pX) { ma_uint32 c; + const ma_uint32 channels = pHPF->channels; const float a = 1 - pHPF->a.f32; const float b = 1 - a; - for (c = 0; c < pHPF->channels; c += 1) { + for (c = 0; c < channels; c += 1) { float r1 = pHPF->r1[c].f32; float x = pX[c]; float y; @@ -37042,10 +37047,11 @@ static MA_INLINE void ma_hpf1_process_pcm_frame_f32(ma_hpf1* pHPF, float* pY, co static MA_INLINE void ma_hpf1_process_pcm_frame_s16(ma_hpf1* pHPF, ma_int16* pY, const ma_int16* pX) { ma_uint32 c; + const ma_uint32 channels = pHPF->channels; const ma_int32 a = ((1 << MA_BIQUAD_FIXED_POINT_SHIFT) - pHPF->a.s32); const ma_int32 b = ((1 << MA_BIQUAD_FIXED_POINT_SHIFT) - a); - for (c = 0; c < pHPF->channels; c += 1) { + for (c = 0; c < channels; c += 1) { ma_int32 r1 = pHPF->r1[c].s32; ma_int32 x = pX[c]; ma_int32 y; @@ -38382,6 +38388,7 @@ static void ma_linear_resampler_interpolate_frame_s16(ma_linear_resampler* pResa { ma_uint32 c; ma_uint32 a; + const ma_uint32 channels = pResampler->config.channels; const ma_uint32 shift = 12; MA_ASSERT(pResampler != NULL); @@ -38389,7 +38396,7 @@ static void ma_linear_resampler_interpolate_frame_s16(ma_linear_resampler* pResa a = (pResampler->inTimeFrac << shift) / pResampler->config.sampleRateOut; - for (c = 0; c < pResampler->config.channels; c += 1) { + for (c = 0; c < channels; c += 1) { ma_int16 s = ma_linear_resampler_mix_s16(pResampler->x0.s16[c], pResampler->x1.s16[c], a, shift); pFrameOut[c] = s; } @@ -38400,13 +38407,14 @@ static void ma_linear_resampler_interpolate_frame_f32(ma_linear_resampler* pResa { ma_uint32 c; float a; + const ma_uint32 channels = pResampler->config.channels; MA_ASSERT(pResampler != NULL); MA_ASSERT(pFrameOut != NULL); a = (float)pResampler->inTimeFrac / pResampler->config.sampleRateOut; - for (c = 0; c < pResampler->config.channels; c += 1) { + for (c = 0; c < channels; c += 1) { float s = ma_mix_f32_fast(pResampler->x0.f32[c], pResampler->x1.f32[c], a); pFrameOut[c] = s; } @@ -48714,20 +48722,21 @@ static MA_INLINE ma_uint64 ma_noise_read_pcm_frames__white(ma_noise* pNoise, voi { ma_uint64 iFrame; ma_uint32 iChannel; + const ma_uint32 channels = pNoise->config.channels; if (pNoise->config.format == ma_format_f32) { float* pFramesOutF32 = (float*)pFramesOut; if (pNoise->config.duplicateChannels) { for (iFrame = 0; iFrame < frameCount; iFrame += 1) { float s = ma_noise_f32_white(pNoise); - for (iChannel = 0; iChannel < pNoise->config.channels; iChannel += 1) { - pFramesOutF32[iFrame*pNoise->config.channels + iChannel] = s; + for (iChannel = 0; iChannel < channels; iChannel += 1) { + pFramesOutF32[iFrame*channels + iChannel] = s; } } } else { for (iFrame = 0; iFrame < frameCount; iFrame += 1) { - for (iChannel = 0; iChannel < pNoise->config.channels; iChannel += 1) { - pFramesOutF32[iFrame*pNoise->config.channels + iChannel] = ma_noise_f32_white(pNoise); + for (iChannel = 0; iChannel < channels; iChannel += 1) { + pFramesOutF32[iFrame*channels + iChannel] = ma_noise_f32_white(pNoise); } } } @@ -48736,31 +48745,31 @@ static MA_INLINE ma_uint64 ma_noise_read_pcm_frames__white(ma_noise* pNoise, voi if (pNoise->config.duplicateChannels) { for (iFrame = 0; iFrame < frameCount; iFrame += 1) { ma_int16 s = ma_noise_s16_white(pNoise); - for (iChannel = 0; iChannel < pNoise->config.channels; iChannel += 1) { - pFramesOutS16[iFrame*pNoise->config.channels + iChannel] = s; + for (iChannel = 0; iChannel < channels; iChannel += 1) { + pFramesOutS16[iFrame*channels + iChannel] = s; } } } else { for (iFrame = 0; iFrame < frameCount; iFrame += 1) { - for (iChannel = 0; iChannel < pNoise->config.channels; iChannel += 1) { - pFramesOutS16[iFrame*pNoise->config.channels + iChannel] = ma_noise_s16_white(pNoise); + for (iChannel = 0; iChannel < channels; iChannel += 1) { + pFramesOutS16[iFrame*channels + iChannel] = ma_noise_s16_white(pNoise); } } } } else { - ma_uint32 bps = ma_get_bytes_per_sample(pNoise->config.format); - ma_uint32 bpf = bps * pNoise->config.channels; + const ma_uint32 bps = ma_get_bytes_per_sample(pNoise->config.format); + const ma_uint32 bpf = bps * channels; if (pNoise->config.duplicateChannels) { for (iFrame = 0; iFrame < frameCount; iFrame += 1) { float s = ma_noise_f32_white(pNoise); - for (iChannel = 0; iChannel < pNoise->config.channels; iChannel += 1) { + for (iChannel = 0; iChannel < channels; iChannel += 1) { ma_pcm_convert(ma_offset_ptr(pFramesOut, iFrame*bpf + iChannel*bps), pNoise->config.format, &s, ma_format_f32, 1, ma_dither_mode_none); } } } else { for (iFrame = 0; iFrame < frameCount; iFrame += 1) { - for (iChannel = 0; iChannel < pNoise->config.channels; iChannel += 1) { + for (iChannel = 0; iChannel < channels; iChannel += 1) { float s = ma_noise_f32_white(pNoise); ma_pcm_convert(ma_offset_ptr(pFramesOut, iFrame*bpf + iChannel*bps), pNoise->config.format, &s, ma_format_f32, 1, ma_dither_mode_none); } @@ -48831,20 +48840,21 @@ static MA_INLINE ma_uint64 ma_noise_read_pcm_frames__pink(ma_noise* pNoise, void { ma_uint64 iFrame; ma_uint32 iChannel; + const ma_uint32 channels = pNoise->config.channels; if (pNoise->config.format == ma_format_f32) { float* pFramesOutF32 = (float*)pFramesOut; if (pNoise->config.duplicateChannels) { for (iFrame = 0; iFrame < frameCount; iFrame += 1) { float s = ma_noise_f32_pink(pNoise, 0); - for (iChannel = 0; iChannel < pNoise->config.channels; iChannel += 1) { - pFramesOutF32[iFrame*pNoise->config.channels + iChannel] = s; + for (iChannel = 0; iChannel < channels; iChannel += 1) { + pFramesOutF32[iFrame*channels + iChannel] = s; } } } else { for (iFrame = 0; iFrame < frameCount; iFrame += 1) { - for (iChannel = 0; iChannel < pNoise->config.channels; iChannel += 1) { - pFramesOutF32[iFrame*pNoise->config.channels + iChannel] = ma_noise_f32_pink(pNoise, iChannel); + for (iChannel = 0; iChannel < channels; iChannel += 1) { + pFramesOutF32[iFrame*channels + iChannel] = ma_noise_f32_pink(pNoise, iChannel); } } } @@ -48853,31 +48863,31 @@ static MA_INLINE ma_uint64 ma_noise_read_pcm_frames__pink(ma_noise* pNoise, void if (pNoise->config.duplicateChannels) { for (iFrame = 0; iFrame < frameCount; iFrame += 1) { ma_int16 s = ma_noise_s16_pink(pNoise, 0); - for (iChannel = 0; iChannel < pNoise->config.channels; iChannel += 1) { - pFramesOutS16[iFrame*pNoise->config.channels + iChannel] = s; + for (iChannel = 0; iChannel < channels; iChannel += 1) { + pFramesOutS16[iFrame*channels + iChannel] = s; } } } else { for (iFrame = 0; iFrame < frameCount; iFrame += 1) { - for (iChannel = 0; iChannel < pNoise->config.channels; iChannel += 1) { - pFramesOutS16[iFrame*pNoise->config.channels + iChannel] = ma_noise_s16_pink(pNoise, iChannel); + for (iChannel = 0; iChannel < channels; iChannel += 1) { + pFramesOutS16[iFrame*channels + iChannel] = ma_noise_s16_pink(pNoise, iChannel); } } } } else { - ma_uint32 bps = ma_get_bytes_per_sample(pNoise->config.format); - ma_uint32 bpf = bps * pNoise->config.channels; + const ma_uint32 bps = ma_get_bytes_per_sample(pNoise->config.format); + const ma_uint32 bpf = bps * channels; if (pNoise->config.duplicateChannels) { for (iFrame = 0; iFrame < frameCount; iFrame += 1) { float s = ma_noise_f32_pink(pNoise, 0); - for (iChannel = 0; iChannel < pNoise->config.channels; iChannel += 1) { + for (iChannel = 0; iChannel < channels; iChannel += 1) { ma_pcm_convert(ma_offset_ptr(pFramesOut, iFrame*bpf + iChannel*bps), pNoise->config.format, &s, ma_format_f32, 1, ma_dither_mode_none); } } } else { for (iFrame = 0; iFrame < frameCount; iFrame += 1) { - for (iChannel = 0; iChannel < pNoise->config.channels; iChannel += 1) { + for (iChannel = 0; iChannel < channels; iChannel += 1) { float s = ma_noise_f32_pink(pNoise, iChannel); ma_pcm_convert(ma_offset_ptr(pFramesOut, iFrame*bpf + iChannel*bps), pNoise->config.format, &s, ma_format_f32, 1, ma_dither_mode_none); } @@ -48911,20 +48921,21 @@ static MA_INLINE ma_uint64 ma_noise_read_pcm_frames__brownian(ma_noise* pNoise, { ma_uint64 iFrame; ma_uint32 iChannel; + const ma_uint32 channels = pNoise->config.channels; if (pNoise->config.format == ma_format_f32) { float* pFramesOutF32 = (float*)pFramesOut; if (pNoise->config.duplicateChannels) { for (iFrame = 0; iFrame < frameCount; iFrame += 1) { float s = ma_noise_f32_brownian(pNoise, 0); - for (iChannel = 0; iChannel < pNoise->config.channels; iChannel += 1) { - pFramesOutF32[iFrame*pNoise->config.channels + iChannel] = s; + for (iChannel = 0; iChannel < channels; iChannel += 1) { + pFramesOutF32[iFrame*channels + iChannel] = s; } } } else { for (iFrame = 0; iFrame < frameCount; iFrame += 1) { - for (iChannel = 0; iChannel < pNoise->config.channels; iChannel += 1) { - pFramesOutF32[iFrame*pNoise->config.channels + iChannel] = ma_noise_f32_brownian(pNoise, iChannel); + for (iChannel = 0; iChannel < channels; iChannel += 1) { + pFramesOutF32[iFrame*channels + iChannel] = ma_noise_f32_brownian(pNoise, iChannel); } } } @@ -48933,31 +48944,31 @@ static MA_INLINE ma_uint64 ma_noise_read_pcm_frames__brownian(ma_noise* pNoise, if (pNoise->config.duplicateChannels) { for (iFrame = 0; iFrame < frameCount; iFrame += 1) { ma_int16 s = ma_noise_s16_brownian(pNoise, 0); - for (iChannel = 0; iChannel < pNoise->config.channels; iChannel += 1) { - pFramesOutS16[iFrame*pNoise->config.channels + iChannel] = s; + for (iChannel = 0; iChannel < channels; iChannel += 1) { + pFramesOutS16[iFrame*channels + iChannel] = s; } } } else { for (iFrame = 0; iFrame < frameCount; iFrame += 1) { - for (iChannel = 0; iChannel < pNoise->config.channels; iChannel += 1) { - pFramesOutS16[iFrame*pNoise->config.channels + iChannel] = ma_noise_s16_brownian(pNoise, iChannel); + for (iChannel = 0; iChannel < channels; iChannel += 1) { + pFramesOutS16[iFrame*channels + iChannel] = ma_noise_s16_brownian(pNoise, iChannel); } } } } else { - ma_uint32 bps = ma_get_bytes_per_sample(pNoise->config.format); - ma_uint32 bpf = bps * pNoise->config.channels; + const ma_uint32 bps = ma_get_bytes_per_sample(pNoise->config.format); + const ma_uint32 bpf = bps * channels; if (pNoise->config.duplicateChannels) { for (iFrame = 0; iFrame < frameCount; iFrame += 1) { float s = ma_noise_f32_brownian(pNoise, 0); - for (iChannel = 0; iChannel < pNoise->config.channels; iChannel += 1) { + for (iChannel = 0; iChannel < channels; iChannel += 1) { ma_pcm_convert(ma_offset_ptr(pFramesOut, iFrame*bpf + iChannel*bps), pNoise->config.format, &s, ma_format_f32, 1, ma_dither_mode_none); } } } else { for (iFrame = 0; iFrame < frameCount; iFrame += 1) { - for (iChannel = 0; iChannel < pNoise->config.channels; iChannel += 1) { + for (iChannel = 0; iChannel < channels; iChannel += 1) { float s = ma_noise_f32_brownian(pNoise, iChannel); ma_pcm_convert(ma_offset_ptr(pFramesOut, iFrame*bpf + iChannel*bps), pNoise->config.format, &s, ma_format_f32, 1, ma_dither_mode_none); } diff --git a/research/miniaudio_engine.h b/research/miniaudio_engine.h index e1d4d5dc..10f65600 100644 --- a/research/miniaudio_engine.h +++ b/research/miniaudio_engine.h @@ -9320,6 +9320,8 @@ MA_API ma_result ma_spatializer_process_pcm_frames(ma_spatializer* pSpatializer, float gain = 1; ma_uint32 iChannel; float channelGainsOut[MA_MAX_CHANNELS]; + const ma_uint32 channelsOut = pSpatializer->config.channelsOut; + const ma_uint32 channelsIn = pSpatializer->config.channelsIn; /* We'll need the listener velocity for doppler pitch calculations. The speed of sound is @@ -9520,12 +9522,12 @@ MA_API ma_result ma_spatializer_process_pcm_frames(ma_spatializer* pSpatializer, be +1 on the X axis. A dot product is performed against the direction vector of the channel and the normalized position of the sound. */ - for (iChannel = 0; iChannel < pSpatializer->config.channelsOut; iChannel += 1) { + for (iChannel = 0; iChannel < channelsOut; iChannel += 1) { channelGainsOut[iChannel] = gain; } /* Convert to our output channel count. */ - ma_convert_pcm_frames_channels_f32((float*)pFramesOut, pSpatializer->config.channelsOut, pChannelMapOut, (const float*)pFramesIn, pSpatializer->config.channelsIn, pChannelMapIn, frameCount); + ma_convert_pcm_frames_channels_f32((float*)pFramesOut, channelsOut, pChannelMapOut, (const float*)pFramesIn, channelsIn, pChannelMapIn, frameCount); /* Calculate our per-channel gains. We do this based on the normalized relative position of the sound and it's @@ -9538,7 +9540,7 @@ MA_API ma_result ma_spatializer_process_pcm_frames(ma_spatializer* pSpatializer, unitPos.y *= distanceInv; unitPos.z *= distanceInv; - for (iChannel = 0; iChannel < pSpatializer->config.channelsOut; iChannel += 1) { + for (iChannel = 0; iChannel < channelsOut; iChannel += 1) { float d = ma_vec3f_dot(unitPos, g_maChannelDirections[pChannelMapOut[iChannel]]); /* @@ -9606,7 +9608,7 @@ MA_API ma_result ma_spatializer_process_pcm_frames(ma_spatializer* pSpatializer, } /* Now we need to apply the volume to each channel. */ - ma_apply_volume_factor_per_channel_f32((float*)pFramesOut, frameCount, pSpatializer->config.channelsOut, channelGainsOut); + ma_apply_volume_factor_per_channel_f32((float*)pFramesOut, frameCount, channelsOut, channelGainsOut); /* Before leaving we'll want to update our doppler pitch so that the caller can apply some From c1451b30a431ccdcae1ca032c68bd7112a1d67d0 Mon Sep 17 00:00:00 2001 From: Steven Noonan Date: Sat, 13 Mar 2021 19:17:24 -0800 Subject: [PATCH 28/43] apply MA_RESTRICT to linear resampler interpolation functions This tells the compiler that pFrameOut does not alias to pointers used within the function, and teaches Clang that the loop is vectorizable. Signed-off-by: Steven Noonan --- miniaudio.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/miniaudio.h b/miniaudio.h index 03ebc713..fb2303bb 100644 --- a/miniaudio.h +++ b/miniaudio.h @@ -38384,7 +38384,7 @@ static MA_INLINE ma_int16 ma_linear_resampler_mix_s16(ma_int16 x, ma_int16 y, ma return (ma_int16)(r >> shift); } -static void ma_linear_resampler_interpolate_frame_s16(ma_linear_resampler* pResampler, ma_int16* pFrameOut) +static void ma_linear_resampler_interpolate_frame_s16(ma_linear_resampler* pResampler, ma_int16* MA_RESTRICT pFrameOut) { ma_uint32 c; ma_uint32 a; @@ -38403,7 +38403,7 @@ static void ma_linear_resampler_interpolate_frame_s16(ma_linear_resampler* pResa } -static void ma_linear_resampler_interpolate_frame_f32(ma_linear_resampler* pResampler, float* pFrameOut) +static void ma_linear_resampler_interpolate_frame_f32(ma_linear_resampler* pResampler, float* MA_RESTRICT pFrameOut) { ma_uint32 c; float a; From 8a1858eba693c7d23db7a24720144b0c894c138d Mon Sep 17 00:00:00 2001 From: Steven Noonan Date: Mon, 15 Mar 2021 04:04:26 -0700 Subject: [PATCH 29/43] use MA_ASSUME for channel counts before loops The range of the value isn't obvious to any compiler, as it could go for one iteration or 4 billion iterations. Adding MA_ASSUME in these places helps the compiler understand the range of possible values, and know how heavily to vectorize (or not vectorize) these loops. Signed-off-by: Steven Noonan --- miniaudio.h | 11 +++++++++++ research/miniaudio_engine.h | 3 +++ 2 files changed, 14 insertions(+) diff --git a/miniaudio.h b/miniaudio.h index fb2303bb..fc0f2ca0 100644 --- a/miniaudio.h +++ b/miniaudio.h @@ -36324,6 +36324,7 @@ static MA_INLINE void ma_biquad_process_pcm_frame_f32__direct_form_2_transposed( const float a1 = pBQ->a1.f32; const float a2 = pBQ->a2.f32; + MA_ASSUME(channels >= MA_MIN_CHANNELS && channels <= MA_MAX_CHANNELS); for (c = 0; c < channels; c += 1) { float r1 = pBQ->r1[c].f32; float r2 = pBQ->r2[c].f32; @@ -36355,6 +36356,7 @@ static MA_INLINE void ma_biquad_process_pcm_frame_s16__direct_form_2_transposed( const ma_int32 a1 = pBQ->a1.s32; const ma_int32 a2 = pBQ->a2.s32; + MA_ASSUME(channels >= MA_MIN_CHANNELS && channels <= MA_MAX_CHANNELS); for (c = 0; c < channels; c += 1) { ma_int32 r1 = pBQ->r1[c].s32; ma_int32 r2 = pBQ->r2[c].s32; @@ -36523,6 +36525,7 @@ static MA_INLINE void ma_lpf1_process_pcm_frame_f32(ma_lpf1* pLPF, float* pY, co const float a = pLPF->a.f32; const float b = 1 - a; + MA_ASSUME(channels >= MA_MIN_CHANNELS && channels <= MA_MAX_CHANNELS); for (c = 0; c < channels; c += 1) { float r1 = pLPF->r1[c].f32; float x = pX[c]; @@ -36542,6 +36545,7 @@ static MA_INLINE void ma_lpf1_process_pcm_frame_s16(ma_lpf1* pLPF, ma_int16* pY, const ma_int32 a = pLPF->a.s32; const ma_int32 b = ((1 << MA_BIQUAD_FIXED_POINT_SHIFT) - a); + MA_ASSUME(channels >= MA_MIN_CHANNELS && channels <= MA_MAX_CHANNELS); for (c = 0; c < channels; c += 1) { ma_int32 r1 = pLPF->r1[c].s32; ma_int32 x = pX[c]; @@ -37032,6 +37036,7 @@ static MA_INLINE void ma_hpf1_process_pcm_frame_f32(ma_hpf1* pHPF, float* pY, co const float a = 1 - pHPF->a.f32; const float b = 1 - a; + MA_ASSUME(channels >= MA_MIN_CHANNELS && channels <= MA_MAX_CHANNELS); for (c = 0; c < channels; c += 1) { float r1 = pHPF->r1[c].f32; float x = pX[c]; @@ -37051,6 +37056,7 @@ static MA_INLINE void ma_hpf1_process_pcm_frame_s16(ma_hpf1* pHPF, ma_int16* pY, const ma_int32 a = ((1 << MA_BIQUAD_FIXED_POINT_SHIFT) - pHPF->a.s32); const ma_int32 b = ((1 << MA_BIQUAD_FIXED_POINT_SHIFT) - a); + MA_ASSUME(channels >= MA_MIN_CHANNELS && channels <= MA_MAX_CHANNELS); for (c = 0; c < channels; c += 1) { ma_int32 r1 = pHPF->r1[c].s32; ma_int32 x = pX[c]; @@ -38396,6 +38402,7 @@ static void ma_linear_resampler_interpolate_frame_s16(ma_linear_resampler* pResa a = (pResampler->inTimeFrac << shift) / pResampler->config.sampleRateOut; + MA_ASSUME(channels >= MA_MIN_CHANNELS && channels <= MA_MAX_CHANNELS); for (c = 0; c < channels; c += 1) { ma_int16 s = ma_linear_resampler_mix_s16(pResampler->x0.s16[c], pResampler->x1.s16[c], a, shift); pFrameOut[c] = s; @@ -38414,6 +38421,7 @@ static void ma_linear_resampler_interpolate_frame_f32(ma_linear_resampler* pResa a = (float)pResampler->inTimeFrac / pResampler->config.sampleRateOut; + MA_ASSUME(channels >= MA_MIN_CHANNELS && channels <= MA_MAX_CHANNELS); for (c = 0; c < channels; c += 1) { float s = ma_mix_f32_fast(pResampler->x0.f32[c], pResampler->x1.f32[c], a); pFrameOut[c] = s; @@ -48723,6 +48731,7 @@ static MA_INLINE ma_uint64 ma_noise_read_pcm_frames__white(ma_noise* pNoise, voi ma_uint64 iFrame; ma_uint32 iChannel; const ma_uint32 channels = pNoise->config.channels; + MA_ASSUME(channels >= MA_MIN_CHANNELS && channels <= MA_MAX_CHANNELS); if (pNoise->config.format == ma_format_f32) { float* pFramesOutF32 = (float*)pFramesOut; @@ -48841,6 +48850,7 @@ static MA_INLINE ma_uint64 ma_noise_read_pcm_frames__pink(ma_noise* pNoise, void ma_uint64 iFrame; ma_uint32 iChannel; const ma_uint32 channels = pNoise->config.channels; + MA_ASSUME(channels >= MA_MIN_CHANNELS && channels <= MA_MAX_CHANNELS); if (pNoise->config.format == ma_format_f32) { float* pFramesOutF32 = (float*)pFramesOut; @@ -48922,6 +48932,7 @@ static MA_INLINE ma_uint64 ma_noise_read_pcm_frames__brownian(ma_noise* pNoise, ma_uint64 iFrame; ma_uint32 iChannel; const ma_uint32 channels = pNoise->config.channels; + MA_ASSUME(channels >= MA_MIN_CHANNELS && channels <= MA_MAX_CHANNELS); if (pNoise->config.format == ma_format_f32) { float* pFramesOutF32 = (float*)pFramesOut; diff --git a/research/miniaudio_engine.h b/research/miniaudio_engine.h index 10f65600..101361df 100644 --- a/research/miniaudio_engine.h +++ b/research/miniaudio_engine.h @@ -9323,6 +9323,9 @@ MA_API ma_result ma_spatializer_process_pcm_frames(ma_spatializer* pSpatializer, const ma_uint32 channelsOut = pSpatializer->config.channelsOut; const ma_uint32 channelsIn = pSpatializer->config.channelsIn; + MA_ASSUME(channelsOut >= MA_MIN_CHANNELS && channelsOut <= MA_MAX_CHANNELS); + MA_ASSUME(channelsIn >= MA_MIN_CHANNELS && channelsIn <= MA_MAX_CHANNELS); + /* We'll need the listener velocity for doppler pitch calculations. The speed of sound is defined by the listener, so we'll grab that here too. From a02f559581d0e506124a048fe7c6cc0fa994f148 Mon Sep 17 00:00:00 2001 From: David Reid Date: Tue, 16 Mar 2021 18:20:14 +1000 Subject: [PATCH 30/43] JACK: Add support for loading JACK from libjack64.dll. --- miniaudio.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/miniaudio.h b/miniaudio.h index 5166f93f..7c86e024 100644 --- a/miniaudio.h +++ b/miniaudio.h @@ -23710,7 +23710,8 @@ static ma_result ma_context_init__jack(ma_context* pContext, const ma_context_co #ifndef MA_NO_RUNTIME_LINKING const char* libjackNames[] = { #ifdef MA_WIN32 - "libjack.dll" + "libjack.dll", + "libjack64.dll" #else "libjack.so", "libjack.so.0" @@ -64487,6 +64488,7 @@ REVISION HISTORY v0.10.33 - TBD - Core Audio: Fix a memory leak. - Core Audio: Fix a bug where the performance profile is not being used by playback devices. + - JACK: Fix loading of 64-bit JACK on Windows. - Add a safety check to the following APIs to prevent a division by zero: - ma_calculate_buffer_size_in_milliseconds_from_frames() - ma_calculate_buffer_size_in_milliseconds_from_milliseconds() From 64749431dd55dea7dfd0fbe0f84b48011f47ac0a Mon Sep 17 00:00:00 2001 From: David Reid Date: Sun, 21 Mar 2021 07:56:29 +1000 Subject: [PATCH 31/43] Update c89atomic. --- miniaudio.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/miniaudio.h b/miniaudio.h index 21913d12..70e43088 100644 --- a/miniaudio.h +++ b/miniaudio.h @@ -8746,28 +8746,28 @@ typedef unsigned char c89atomic_bool; static C89ATOMIC_INLINE c89atomic_uint8 c89atomic_load_explicit_8(volatile const c89atomic_uint8* ptr, c89atomic_memory_order order) { (void)order; - return c89atomic_compare_and_swap_8(ptr, 0, 0); + return c89atomic_compare_and_swap_8((c89atomic_uint8*)ptr, 0, 0); } #endif #if defined(C89ATOMIC_HAS_16) static C89ATOMIC_INLINE c89atomic_uint16 c89atomic_load_explicit_16(volatile const c89atomic_uint16* ptr, c89atomic_memory_order order) { (void)order; - return c89atomic_compare_and_swap_16(ptr, 0, 0); + return c89atomic_compare_and_swap_16((c89atomic_uint16*)ptr, 0, 0); } #endif #if defined(C89ATOMIC_HAS_32) static C89ATOMIC_INLINE c89atomic_uint32 c89atomic_load_explicit_32(volatile const c89atomic_uint32* ptr, c89atomic_memory_order order) { (void)order; - return c89atomic_compare_and_swap_32(ptr, 0, 0); + return c89atomic_compare_and_swap_32((c89atomic_uint32*)ptr, 0, 0); } #endif #if defined(C89ATOMIC_HAS_64) static C89ATOMIC_INLINE c89atomic_uint64 c89atomic_load_explicit_64(volatile const c89atomic_uint64* ptr, c89atomic_memory_order order) { (void)order; - return c89atomic_compare_and_swap_64(ptr, 0, 0); + return c89atomic_compare_and_swap_64((c89atomic_uint64*)ptr, 0, 0); } #endif #if defined(C89ATOMIC_HAS_8) From ba3e73cb222d8ec204c13d4222b556f6a1a3c9ca Mon Sep 17 00:00:00 2001 From: David Reid Date: Sun, 21 Mar 2021 07:57:53 +1000 Subject: [PATCH 32/43] Update revision history. --- miniaudio.h | 1 + 1 file changed, 1 insertion(+) diff --git a/miniaudio.h b/miniaudio.h index 70e43088..799b2f78 100644 --- a/miniaudio.h +++ b/miniaudio.h @@ -64537,6 +64537,7 @@ v0.10.33 - TBD - Add a safety check to the following APIs to prevent a division by zero: - ma_calculate_buffer_size_in_milliseconds_from_frames() - ma_calculate_buffer_size_in_milliseconds_from_milliseconds() + - Fix compilation errors relating to c89atomic. v0.10.32 - 2021-02-23 - WASAPI: Fix a deadlock in exclusive mode. From eef66940c2c31770f3ef84e4de278f28eb206a58 Mon Sep 17 00:00:00 2001 From: David Reid Date: Sun, 21 Mar 2021 08:07:26 +1000 Subject: [PATCH 33/43] Fix a bug when calculating buffer sizes. This fixes the following APIs: * ma_calculate_buffer_size_in_milliseconds_from_frames() * ma_calculate_buffer_size_in_frames_from_milliseconds() Public issue https://github.com/mackron/miniaudio/issues/283 --- miniaudio.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/miniaudio.h b/miniaudio.h index 799b2f78..af4ca0e9 100644 --- a/miniaudio.h +++ b/miniaudio.h @@ -33576,7 +33576,7 @@ MA_API ma_uint32 ma_calculate_buffer_size_in_milliseconds_from_frames(ma_uint32 return 0; } - return bufferSizeInFrames / (sampleRate/1000); + return bufferSizeInFrames*1000 / sampleRate; } MA_API ma_uint32 ma_calculate_buffer_size_in_frames_from_milliseconds(ma_uint32 bufferSizeInMilliseconds, ma_uint32 sampleRate) @@ -33586,7 +33586,7 @@ MA_API ma_uint32 ma_calculate_buffer_size_in_frames_from_milliseconds(ma_uint32 return 0; } - return bufferSizeInMilliseconds * (sampleRate/1000); + return bufferSizeInMilliseconds*sampleRate / 1000; } MA_API void ma_copy_pcm_frames(void* dst, const void* src, ma_uint64 frameCount, ma_format format, ma_uint32 channels) @@ -64534,9 +64534,9 @@ v0.10.33 - TBD - Core Audio: Fix a memory leak. - Core Audio: Fix a bug where the performance profile is not being used by playback devices. - JACK: Fix loading of 64-bit JACK on Windows. - - Add a safety check to the following APIs to prevent a division by zero: + - Fix a calculation error and add a safety check to the following APIs to prevent a division by zero: - ma_calculate_buffer_size_in_milliseconds_from_frames() - - ma_calculate_buffer_size_in_milliseconds_from_milliseconds() + - ma_calculate_buffer_size_in_frames_from_milliseconds() - Fix compilation errors relating to c89atomic. v0.10.32 - 2021-02-23 From 045ee8ae1896ad1dee90dc2b38b66ae5ed1fadec Mon Sep 17 00:00:00 2001 From: David Reid Date: Sun, 21 Mar 2021 09:38:21 +1000 Subject: [PATCH 34/43] Experimental fix for a memory leak in the resource manager. --- research/miniaudio_engine.h | 108 +++++++++++++++--------------------- 1 file changed, 45 insertions(+), 63 deletions(-) diff --git a/research/miniaudio_engine.h b/research/miniaudio_engine.h index 101361df..808b81c1 100644 --- a/research/miniaudio_engine.h +++ b/research/miniaudio_engine.h @@ -6361,75 +6361,31 @@ static ma_result ma_resource_manager_data_buffer_uninit_internal(ma_resource_man ma_resource_manager_data_buffer_uninit_connector(pDataBuffer->pResourceManager, pDataBuffer); pDataBuffer->connectorType = ma_resource_manager_data_buffer_connector_unknown; - /* Free the node last. */ - ma_resource_manager_data_buffer_node_free(pDataBuffer->pResourceManager, pDataBuffer->pNode); + /* With the connector uninitialized we can decrement the ref count of the node and free it if required. */ + ma_resource_manager_data_buffer_bst_lock(pDataBuffer->pResourceManager); + { + ma_result result; + ma_uint32 refCount; - return MA_SUCCESS; -} - -static ma_result ma_resource_manager_data_buffer_uninit_nolock(ma_resource_manager_data_buffer* pDataBuffer) -{ - ma_uint32 result; - ma_uint32 refCount; - - MA_ASSERT(pDataBuffer != NULL); - - result = ma_resource_manager_data_buffer_node_decrement_ref(pDataBuffer->pResourceManager, pDataBuffer->pNode, &refCount); - if (result != MA_SUCCESS) { - return result; - } - - /* If the reference count has hit zero it means we need to delete the data buffer and it's backing data (so long as it's owned by the resource manager). */ - if (refCount == 0) { - ma_bool32 asyncUninit = MA_TRUE; - - result = ma_resource_manager_data_buffer_node_remove(pDataBuffer->pResourceManager, pDataBuffer->pNode); + result = ma_resource_manager_data_buffer_node_decrement_ref(pDataBuffer->pResourceManager, pDataBuffer->pNode, &refCount); if (result != MA_SUCCESS) { - return result; /* An error occurred when trying to remove the data buffer. This should never happen. */ + return result; } - if (ma_resource_manager_data_buffer_node_result(pDataBuffer->pNode) == MA_SUCCESS) { - asyncUninit = MA_FALSE; - } - - /* - The data buffer has been removed from the BST so now we need to delete the underyling data. This needs to be done in a separate thread. We don't - want to delete anything if the data is owned by the application. Also, just to be safe, we set the result to MA_UNAVAILABLE. - */ - c89atomic_exchange_i32(&pDataBuffer->pNode->result, MA_UNAVAILABLE); - - if (asyncUninit == MA_FALSE) { - /* The data buffer can be deleted synchronously. */ - return ma_resource_manager_data_buffer_uninit_internal(pDataBuffer); - } else { - /* - The data buffer needs to be deleted asynchronously because it's still loading. With the status set to MA_UNAVAILABLE, no more pages will - be loaded and the uninitialization should happen fairly quickly. Since the caller owns the data buffer, we need to wait for this event - to get processed before returning. - */ - ma_resource_manager_inline_notification notification; - ma_job job; - - result = ma_resource_manager_inline_notification_init(pDataBuffer->pResourceManager, ¬ification); + if (refCount == 0) { + result = ma_resource_manager_data_buffer_node_remove(pDataBuffer->pResourceManager, pDataBuffer->pNode); if (result != MA_SUCCESS) { - return result; /* Failed to create the notification. This should rarely, if ever, happen. */ + return result; /* An error occurred when trying to remove the data buffer. This should never happen. */ } - job = ma_job_init(MA_JOB_FREE_DATA_BUFFER); - job.order = ma_resource_manager_data_buffer_next_execution_order(pDataBuffer); - job.freeDataBuffer.pDataBuffer = pDataBuffer; - job.freeDataBuffer.pNotification = ¬ification; + /* Mark the node as unavailable just to be safe. */ + c89atomic_exchange_i32(&pDataBuffer->pNode->result, MA_UNAVAILABLE); - result = ma_resource_manager_post_job(pDataBuffer->pResourceManager, &job); - if (result != MA_SUCCESS) { - ma_resource_manager_inline_notification_uninit(¬ification); - return result; - } - - ma_resource_manager_inline_notification_wait(¬ification); - ma_resource_manager_inline_notification_uninit(¬ification); + /* Free the node last. */ + ma_resource_manager_data_buffer_node_free(pDataBuffer->pResourceManager, pDataBuffer->pNode); } } + ma_resource_manager_data_buffer_bst_unlock(pDataBuffer->pResourceManager); return MA_SUCCESS; } @@ -6442,11 +6398,37 @@ MA_API ma_result ma_resource_manager_data_buffer_uninit(ma_resource_manager_data return MA_INVALID_ARGS; } - ma_resource_manager_data_buffer_bst_lock(pDataBuffer->pResourceManager); - { - result = ma_resource_manager_data_buffer_uninit_nolock(pDataBuffer); + if (ma_resource_manager_data_buffer_node_result(pDataBuffer->pNode) == MA_SUCCESS) { + /* The data buffer can be deleted synchronously. */ + return ma_resource_manager_data_buffer_uninit_internal(pDataBuffer); + } else { + /* + The data buffer needs to be deleted asynchronously because it's still loading. With the status set to MA_UNAVAILABLE, no more pages will + be loaded and the uninitialization should happen fairly quickly. Since the caller owns the data buffer, we need to wait for this event + to get processed before returning. + */ + ma_resource_manager_inline_notification notification; + ma_job job; + + result = ma_resource_manager_inline_notification_init(pDataBuffer->pResourceManager, ¬ification); + if (result != MA_SUCCESS) { + return result; /* Failed to create the notification. This should rarely, if ever, happen. */ + } + + job = ma_job_init(MA_JOB_FREE_DATA_BUFFER); + job.order = ma_resource_manager_data_buffer_next_execution_order(pDataBuffer); + job.freeDataBuffer.pDataBuffer = pDataBuffer; + job.freeDataBuffer.pNotification = ¬ification; + + result = ma_resource_manager_post_job(pDataBuffer->pResourceManager, &job); + if (result != MA_SUCCESS) { + ma_resource_manager_inline_notification_uninit(¬ification); + return result; + } + + ma_resource_manager_inline_notification_wait(¬ification); + ma_resource_manager_inline_notification_uninit(¬ification); } - ma_resource_manager_data_buffer_bst_unlock(pDataBuffer->pResourceManager); return result; } From 881fa6063e495a1dd57c1447a76f065c2bb1c642 Mon Sep 17 00:00:00 2001 From: David Reid Date: Fri, 2 Apr 2021 08:52:00 +1000 Subject: [PATCH 35/43] Update dr_flac. --- extras/dr_flac.h | 71 ++++++++++++++++++++++++++++++++++++++++-------- miniaudio.h | 61 ++++++++++++++++++++++++++++++++++------- 2 files changed, 111 insertions(+), 21 deletions(-) diff --git a/extras/dr_flac.h b/extras/dr_flac.h index 2dcddb58..a797350a 100644 --- a/extras/dr_flac.h +++ b/extras/dr_flac.h @@ -1,6 +1,6 @@ /* FLAC audio decoder. Choice of public domain or MIT-0. See license statements at the end of this file. -dr_flac - v0.12.28 - 2021-02-21 +dr_flac - v0.12.29 - 2021-04-02 David Reid - mackron@gmail.com @@ -232,7 +232,7 @@ extern "C" { #define DRFLAC_VERSION_MAJOR 0 #define DRFLAC_VERSION_MINOR 12 -#define DRFLAC_VERSION_REVISION 28 +#define DRFLAC_VERSION_REVISION 29 #define DRFLAC_VERSION_STRING DRFLAC_XSTRINGIFY(DRFLAC_VERSION_MAJOR) "." DRFLAC_XSTRINGIFY(DRFLAC_VERSION_MINOR) "." DRFLAC_XSTRINGIFY(DRFLAC_VERSION_REVISION) #include /* For size_t. */ @@ -1577,6 +1577,27 @@ static DRFLAC_INLINE drflac_bool32 drflac_has_sse41(void) #if ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)) #define DRFLAC_HAS_BYTESWAP16_INTRINSIC #endif +#elif defined(__WATCOMC__) && defined(__386__) + #define DRFLAC_HAS_BYTESWAP16_INTRINSIC + #define DRFLAC_HAS_BYTESWAP32_INTRINSIC + #define DRFLAC_HAS_BYTESWAP64_INTRINSIC + extern __inline drflac_uint16 _watcom_bswap16(drflac_uint16); + extern __inline drflac_uint32 _watcom_bswap32(drflac_uint32); + extern __inline drflac_uint64 _watcom_bswap64(drflac_uint64); +#pragma aux _watcom_bswap16 = \ + "xchg al, ah" \ + parm [ax] \ + modify [ax]; +#pragma aux _watcom_bswap32 = \ + "bswap eax" \ + parm [eax] \ + modify [eax]; +#pragma aux _watcom_bswap64 = \ + "bswap eax" \ + "bswap edx" \ + "xchg eax,edx" \ + parm [eax edx] \ + modify [eax edx]; #endif @@ -1800,6 +1821,8 @@ static DRFLAC_INLINE drflac_uint16 drflac__swap_endian_uint16(drflac_uint16 n) return _byteswap_ushort(n); #elif defined(__GNUC__) || defined(__clang__) return __builtin_bswap16(n); + #elif defined(__WATCOMC__) && defined(__386__) + return _watcom_bswap16(n); #else #error "This compiler does not support the byte swap intrinsic." #endif @@ -1829,6 +1852,8 @@ static DRFLAC_INLINE drflac_uint32 drflac__swap_endian_uint32(drflac_uint32 n) #else return __builtin_bswap32(n); #endif + #elif defined(__WATCOMC__) && defined(__386__) + return _watcom_bswap32(n); #else #error "This compiler does not support the byte swap intrinsic." #endif @@ -1847,6 +1872,8 @@ static DRFLAC_INLINE drflac_uint64 drflac__swap_endian_uint64(drflac_uint64 n) return _byteswap_uint64(n); #elif defined(__GNUC__) || defined(__clang__) return __builtin_bswap64(n); + #elif defined(__WATCOMC__) && defined(__386__) + return _watcom_bswap64(n); #else #error "This compiler does not support the byte swap intrinsic." #endif @@ -2654,6 +2681,9 @@ static drflac_bool32 drflac__find_and_seek_to_next_sync_code(drflac_bs* bs) #if defined(_MSC_VER) && _MSC_VER >= 1400 && (defined(DRFLAC_X64) || defined(DRFLAC_X86)) && !defined(__clang__) #define DRFLAC_IMPLEMENT_CLZ_MSVC #endif +#if defined(__WATCOMC__) && defined(__386__) +#define DRFLAC_IMPLEMENT_CLZ_WATCOM +#endif static DRFLAC_INLINE drflac_uint32 drflac__clz_software(drflac_cache_t x) { @@ -2801,6 +2831,16 @@ static DRFLAC_INLINE drflac_uint32 drflac__clz_msvc(drflac_cache_t x) } #endif +#ifdef DRFLAC_IMPLEMENT_CLZ_WATCOM +static __inline drflac_uint32 drflac__clz_watcom (drflac_uint32); +#pragma aux drflac__clz_watcom = \ + "bsr eax, eax" \ + "xor eax, 31" \ + parm [eax] nomemory \ + value [eax] \ + modify exact [eax] nomemory; +#endif + static DRFLAC_INLINE drflac_uint32 drflac__clz(drflac_cache_t x) { #ifdef DRFLAC_IMPLEMENT_CLZ_LZCNT @@ -2811,6 +2851,8 @@ static DRFLAC_INLINE drflac_uint32 drflac__clz(drflac_cache_t x) { #ifdef DRFLAC_IMPLEMENT_CLZ_MSVC return drflac__clz_msvc(x); +#elif defined(DRFLAC_IMPLEMENT_CLZ_WATCOM) + return (x == 0) ? sizeof(x)*8 : drflac__clz_watcom(x); #else return drflac__clz_software(x); #endif @@ -3194,7 +3236,6 @@ static drflac_bool32 drflac__decode_samples_with_residual__rice__reference(drfla drflac_uint32 i; DRFLAC_ASSERT(bs != NULL); - DRFLAC_ASSERT(count > 0); DRFLAC_ASSERT(pSamplesOut != NULL); for (i = 0; i < count; ++i) { @@ -3576,7 +3617,6 @@ static drflac_bool32 drflac__decode_samples_with_residual__rice__scalar_zeroorde drflac_uint32 i; DRFLAC_ASSERT(bs != NULL); - DRFLAC_ASSERT(count > 0); DRFLAC_ASSERT(pSamplesOut != NULL); (void)bitsPerSample; @@ -3622,7 +3662,6 @@ static drflac_bool32 drflac__decode_samples_with_residual__rice__scalar(drflac_b drflac_uint32 i; DRFLAC_ASSERT(bs != NULL); - DRFLAC_ASSERT(count > 0); DRFLAC_ASSERT(pSamplesOut != NULL); if (order == 0) { @@ -4176,7 +4215,6 @@ static drflac_bool32 drflac__decode_samples_with_residual__rice__sse41_64(drflac static drflac_bool32 drflac__decode_samples_with_residual__rice__sse41(drflac_bs* bs, drflac_uint32 bitsPerSample, drflac_uint32 count, drflac_uint8 riceParam, drflac_uint32 order, drflac_int32 shift, const drflac_int32* coefficients, drflac_int32* pSamplesOut) { DRFLAC_ASSERT(bs != NULL); - DRFLAC_ASSERT(count > 0); DRFLAC_ASSERT(pSamplesOut != NULL); /* In my testing the order is rarely > 12, so in this case I'm going to simplify the SSE implementation by only handling order <= 12. */ @@ -4675,7 +4713,6 @@ static drflac_bool32 drflac__decode_samples_with_residual__rice__neon_64(drflac_ static drflac_bool32 drflac__decode_samples_with_residual__rice__neon(drflac_bs* bs, drflac_uint32 bitsPerSample, drflac_uint32 count, drflac_uint8 riceParam, drflac_uint32 order, drflac_int32 shift, const drflac_int32* coefficients, drflac_int32* pSamplesOut) { DRFLAC_ASSERT(bs != NULL); - DRFLAC_ASSERT(count > 0); DRFLAC_ASSERT(pSamplesOut != NULL); /* In my testing the order is rarely > 12, so in this case I'm going to simplify the NEON implementation by only handling order <= 12. */ @@ -4718,7 +4755,6 @@ static drflac_bool32 drflac__read_and_seek_residual__rice(drflac_bs* bs, drflac_ drflac_uint32 i; DRFLAC_ASSERT(bs != NULL); - DRFLAC_ASSERT(count > 0); for (i = 0; i < count; ++i) { if (!drflac__seek_rice_parts(bs, riceParam)) { @@ -4734,7 +4770,6 @@ static drflac_bool32 drflac__decode_samples_with_residual__unencoded(drflac_bs* drflac_uint32 i; DRFLAC_ASSERT(bs != NULL); - DRFLAC_ASSERT(count > 0); DRFLAC_ASSERT(unencodedBitsPerSample <= 31); /* <-- unencodedBitsPerSample is a 5 bit number, so cannot exceed 31. */ DRFLAC_ASSERT(pSamplesOut != NULL); @@ -4798,7 +4833,7 @@ static drflac_bool32 drflac__decode_samples_with_residual(drflac_bs* bs, drflac_ } /* Validation check. */ - if ((blockSize / (1 << partitionOrder)) <= order) { + if ((blockSize / (1 << partitionOrder)) < order) { return DRFLAC_FALSE; } @@ -11348,6 +11383,7 @@ DRFLAC_API drflac_bool32 drflac_seek_to_pcm_frame(drflac* pFlac, drflac_uint64 p return drflac__seek_to_first_frame(pFlac); } else { drflac_bool32 wasSuccessful = DRFLAC_FALSE; + drflac_uint64 originalPCMFrame = pFlac->currentPCMFrame; /* Clamp the sample to the end. */ if (pcmFrameIndex > pFlac->totalPCMFrameCount) { @@ -11405,7 +11441,16 @@ DRFLAC_API drflac_bool32 drflac_seek_to_pcm_frame(drflac* pFlac, drflac_uint64 p } } - pFlac->currentPCMFrame = pcmFrameIndex; + if (wasSuccessful) { + pFlac->currentPCMFrame = pcmFrameIndex; + } else { + /* Seek failed. Try putting the decoder back to it's original state. */ + if (drflac_seek_to_pcm_frame(pFlac, originalPCMFrame) == DRFLAC_FALSE) { + /* Failed to seek back to the original PCM frame. Fall back to 0. */ + drflac_seek_to_pcm_frame(pFlac, 0); + } + } + return wasSuccessful; } } @@ -11806,6 +11851,10 @@ DRFLAC_API drflac_bool32 drflac_next_cuesheet_track(drflac_cuesheet_track_iterat /* REVISION HISTORY ================ +v0.12.29 - 2021-04-02 + - Fix a bug where the running PCM frame index is set to an invalid value when over-seeking. + - Fix a decoding error due to an incorrect validation check. + v0.12.28 - 2021-02-21 - Fix a warning due to referencing _MSC_VER when it is undefined. diff --git a/miniaudio.h b/miniaudio.h index af4ca0e9..4a0e97a2 100644 --- a/miniaudio.h +++ b/miniaudio.h @@ -44832,7 +44832,7 @@ extern "C" { #define DRFLAC_XSTRINGIFY(x) DRFLAC_STRINGIFY(x) #define DRFLAC_VERSION_MAJOR 0 #define DRFLAC_VERSION_MINOR 12 -#define DRFLAC_VERSION_REVISION 28 +#define DRFLAC_VERSION_REVISION 29 #define DRFLAC_VERSION_STRING DRFLAC_XSTRINGIFY(DRFLAC_VERSION_MAJOR) "." DRFLAC_XSTRINGIFY(DRFLAC_VERSION_MINOR) "." DRFLAC_XSTRINGIFY(DRFLAC_VERSION_REVISION) #include typedef signed char drflac_int8; @@ -53006,6 +53006,27 @@ static DRFLAC_INLINE drflac_bool32 drflac_has_sse41(void) #if ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)) #define DRFLAC_HAS_BYTESWAP16_INTRINSIC #endif +#elif defined(__WATCOMC__) && defined(__386__) + #define DRFLAC_HAS_BYTESWAP16_INTRINSIC + #define DRFLAC_HAS_BYTESWAP32_INTRINSIC + #define DRFLAC_HAS_BYTESWAP64_INTRINSIC + extern __inline drflac_uint16 _watcom_bswap16(drflac_uint16); + extern __inline drflac_uint32 _watcom_bswap32(drflac_uint32); + extern __inline drflac_uint64 _watcom_bswap64(drflac_uint64); +#pragma aux _watcom_bswap16 = \ + "xchg al, ah" \ + parm [ax] \ + modify [ax]; +#pragma aux _watcom_bswap32 = \ + "bswap eax" \ + parm [eax] \ + modify [eax]; +#pragma aux _watcom_bswap64 = \ + "bswap eax" \ + "bswap edx" \ + "xchg eax,edx" \ + parm [eax edx] \ + modify [eax edx]; #endif #ifndef DRFLAC_ASSERT #include @@ -53187,6 +53208,8 @@ static DRFLAC_INLINE drflac_uint16 drflac__swap_endian_uint16(drflac_uint16 n) return _byteswap_ushort(n); #elif defined(__GNUC__) || defined(__clang__) return __builtin_bswap16(n); + #elif defined(__WATCOMC__) && defined(__386__) + return _watcom_bswap16(n); #else #error "This compiler does not support the byte swap intrinsic." #endif @@ -53214,6 +53237,8 @@ static DRFLAC_INLINE drflac_uint32 drflac__swap_endian_uint32(drflac_uint32 n) #else return __builtin_bswap32(n); #endif + #elif defined(__WATCOMC__) && defined(__386__) + return _watcom_bswap32(n); #else #error "This compiler does not support the byte swap intrinsic." #endif @@ -53231,6 +53256,8 @@ static DRFLAC_INLINE drflac_uint64 drflac__swap_endian_uint64(drflac_uint64 n) return _byteswap_uint64(n); #elif defined(__GNUC__) || defined(__clang__) return __builtin_bswap64(n); + #elif defined(__WATCOMC__) && defined(__386__) + return _watcom_bswap64(n); #else #error "This compiler does not support the byte swap intrinsic." #endif @@ -53848,6 +53875,9 @@ static drflac_bool32 drflac__find_and_seek_to_next_sync_code(drflac_bs* bs) #if defined(_MSC_VER) && _MSC_VER >= 1400 && (defined(DRFLAC_X64) || defined(DRFLAC_X86)) && !defined(__clang__) #define DRFLAC_IMPLEMENT_CLZ_MSVC #endif +#if defined(__WATCOMC__) && defined(__386__) +#define DRFLAC_IMPLEMENT_CLZ_WATCOM +#endif static DRFLAC_INLINE drflac_uint32 drflac__clz_software(drflac_cache_t x) { drflac_uint32 n; @@ -53960,6 +53990,15 @@ static DRFLAC_INLINE drflac_uint32 drflac__clz_msvc(drflac_cache_t x) return sizeof(x)*8 - n - 1; } #endif +#ifdef DRFLAC_IMPLEMENT_CLZ_WATCOM +static __inline drflac_uint32 drflac__clz_watcom (drflac_uint32); +#pragma aux drflac__clz_watcom = \ + "bsr eax, eax" \ + "xor eax, 31" \ + parm [eax] nomemory \ + value [eax] \ + modify exact [eax] nomemory; +#endif static DRFLAC_INLINE drflac_uint32 drflac__clz(drflac_cache_t x) { #ifdef DRFLAC_IMPLEMENT_CLZ_LZCNT @@ -53970,6 +54009,8 @@ static DRFLAC_INLINE drflac_uint32 drflac__clz(drflac_cache_t x) { #ifdef DRFLAC_IMPLEMENT_CLZ_MSVC return drflac__clz_msvc(x); +#elif defined(DRFLAC_IMPLEMENT_CLZ_WATCOM) + return (x == 0) ? sizeof(x)*8 : drflac__clz_watcom(x); #else return drflac__clz_software(x); #endif @@ -54286,7 +54327,6 @@ static drflac_bool32 drflac__decode_samples_with_residual__rice__reference(drfla { drflac_uint32 i; DRFLAC_ASSERT(bs != NULL); - DRFLAC_ASSERT(count > 0); DRFLAC_ASSERT(pSamplesOut != NULL); for (i = 0; i < count; ++i) { drflac_uint32 zeroCounter = 0; @@ -54555,7 +54595,6 @@ static drflac_bool32 drflac__decode_samples_with_residual__rice__scalar_zeroorde drflac_uint32 riceParamMask; drflac_uint32 i; DRFLAC_ASSERT(bs != NULL); - DRFLAC_ASSERT(count > 0); DRFLAC_ASSERT(pSamplesOut != NULL); (void)bitsPerSample; (void)order; @@ -54590,7 +54629,6 @@ static drflac_bool32 drflac__decode_samples_with_residual__rice__scalar(drflac_b const drflac_int32* pSamplesOutEnd; drflac_uint32 i; DRFLAC_ASSERT(bs != NULL); - DRFLAC_ASSERT(count > 0); DRFLAC_ASSERT(pSamplesOut != NULL); if (order == 0) { return drflac__decode_samples_with_residual__rice__scalar_zeroorder(bs, bitsPerSample, count, riceParam, order, shift, coefficients, pSamplesOut); @@ -55009,7 +55047,6 @@ static drflac_bool32 drflac__decode_samples_with_residual__rice__sse41_64(drflac static drflac_bool32 drflac__decode_samples_with_residual__rice__sse41(drflac_bs* bs, drflac_uint32 bitsPerSample, drflac_uint32 count, drflac_uint8 riceParam, drflac_uint32 order, drflac_int32 shift, const drflac_int32* coefficients, drflac_int32* pSamplesOut) { DRFLAC_ASSERT(bs != NULL); - DRFLAC_ASSERT(count > 0); DRFLAC_ASSERT(pSamplesOut != NULL); if (order > 0 && order <= 12) { if (bitsPerSample+shift > 32) { @@ -55360,7 +55397,6 @@ static drflac_bool32 drflac__decode_samples_with_residual__rice__neon_64(drflac_ static drflac_bool32 drflac__decode_samples_with_residual__rice__neon(drflac_bs* bs, drflac_uint32 bitsPerSample, drflac_uint32 count, drflac_uint8 riceParam, drflac_uint32 order, drflac_int32 shift, const drflac_int32* coefficients, drflac_int32* pSamplesOut) { DRFLAC_ASSERT(bs != NULL); - DRFLAC_ASSERT(count > 0); DRFLAC_ASSERT(pSamplesOut != NULL); if (order > 0 && order <= 12) { if (bitsPerSample+shift > 32) { @@ -55396,7 +55432,6 @@ static drflac_bool32 drflac__read_and_seek_residual__rice(drflac_bs* bs, drflac_ { drflac_uint32 i; DRFLAC_ASSERT(bs != NULL); - DRFLAC_ASSERT(count > 0); for (i = 0; i < count; ++i) { if (!drflac__seek_rice_parts(bs, riceParam)) { return DRFLAC_FALSE; @@ -55408,7 +55443,6 @@ static drflac_bool32 drflac__decode_samples_with_residual__unencoded(drflac_bs* { drflac_uint32 i; DRFLAC_ASSERT(bs != NULL); - DRFLAC_ASSERT(count > 0); DRFLAC_ASSERT(unencodedBitsPerSample <= 31); DRFLAC_ASSERT(pSamplesOut != NULL); for (i = 0; i < count; ++i) { @@ -55449,7 +55483,7 @@ static drflac_bool32 drflac__decode_samples_with_residual(drflac_bs* bs, drflac_ if (partitionOrder > 8) { return DRFLAC_FALSE; } - if ((blockSize / (1 << partitionOrder)) <= order) { + if ((blockSize / (1 << partitionOrder)) < order) { return DRFLAC_FALSE; } samplesInPartition = (blockSize / (1 << partitionOrder)) - order; @@ -60594,6 +60628,7 @@ DRFLAC_API drflac_bool32 drflac_seek_to_pcm_frame(drflac* pFlac, drflac_uint64 p return drflac__seek_to_first_frame(pFlac); } else { drflac_bool32 wasSuccessful = DRFLAC_FALSE; + drflac_uint64 originalPCMFrame = pFlac->currentPCMFrame; if (pcmFrameIndex > pFlac->totalPCMFrameCount) { pcmFrameIndex = pFlac->totalPCMFrameCount; } @@ -60634,7 +60669,13 @@ DRFLAC_API drflac_bool32 drflac_seek_to_pcm_frame(drflac* pFlac, drflac_uint64 p wasSuccessful = drflac__seek_to_pcm_frame__brute_force(pFlac, pcmFrameIndex); } } - pFlac->currentPCMFrame = pcmFrameIndex; + if (wasSuccessful) { + pFlac->currentPCMFrame = pcmFrameIndex; + } else { + if (drflac_seek_to_pcm_frame(pFlac, originalPCMFrame) == DRFLAC_FALSE) { + drflac_seek_to_pcm_frame(pFlac, 0); + } + } return wasSuccessful; } } From 88687fdc439ebf1e04ae2609abf720ff6c1c3187 Mon Sep 17 00:00:00 2001 From: David Reid Date: Fri, 2 Apr 2021 09:27:08 +1000 Subject: [PATCH 36/43] Try fixing a bug with calculating the relative position of a sound. --- research/miniaudio_engine.c | 8 +++++--- research/miniaudio_engine.h | 12 ++++++------ 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/research/miniaudio_engine.c b/research/miniaudio_engine.c index 3f8a5fc7..21eb9638 100644 --- a/research/miniaudio_engine.c +++ b/research/miniaudio_engine.c @@ -188,10 +188,12 @@ int main(int argc, char** argv) } //ma_spatializer_set_position(&g_spatializer, ma_vec3f_init_3f(posX, 0, posZ)); - ma_sound_set_position(&sound, posX, 0, posZ); - ma_sound_set_velocity(&sound, step*1000, 0, 0); + ma_sound_set_position(&sound, 0, 0, -2); + ma_engine_listener_set_position(&engine, 0, 0, 0, -20); + ma_engine_listener_set_direction(&engine, 0, -1, 0, 0); + //ma_sound_set_velocity(&sound, step*1000, 0, 0); - //ma_engine_listener_set_direciton(&engine, (float)ma_cos(angle), 0, (float)ma_sin(angle)); + ma_engine_listener_set_direction(&engine, 0, (float)ma_cos(angle), 0, (float)ma_sin(angle)); angle += stepAngle; ma_sleep(1); diff --git a/research/miniaudio_engine.h b/research/miniaudio_engine.h index 808b81c1..85c19a3a 100644 --- a/research/miniaudio_engine.h +++ b/research/miniaudio_engine.h @@ -9376,17 +9376,17 @@ MA_API ma_result ma_spatializer_process_pcm_frames(ma_spatializer* pSpatializer, */ v = pSpatializer->position; #if 1 - { - relativePos.x = m[0][0] * v.x + m[1][0] * v.y + m[2][0] * v.z + m[3][0] * 1; - relativePos.y = m[0][1] * v.x + m[1][1] * v.y + m[2][1] * v.z + m[3][1] * 1; - relativePos.z = m[0][2] * v.x + m[1][2] * v.y + m[2][2] * v.z + m[3][2] * 1; - } - #else { relativePos.x = m[0][0] * v.x + m[0][1] * v.y + m[0][2] * v.z + m[0][3] * 1; relativePos.y = m[1][0] * v.x + m[1][1] * v.y + m[1][2] * v.z + m[1][3] * 1; relativePos.z = m[2][0] * v.x + m[2][1] * v.y + m[2][2] * v.z + m[2][3] * 1; } + #else + { + relativePos.x = m[0][0] * v.x + m[1][0] * v.y + m[2][0] * v.z + m[3][0] * 1; + relativePos.y = m[0][1] * v.x + m[1][1] * v.y + m[2][1] * v.z + m[3][1] * 1; + relativePos.z = m[0][2] * v.x + m[1][2] * v.y + m[2][2] * v.z + m[3][2] * 1; + } #endif /* From ca5023415f0eb37bcf743451f33cad68e7af000b Mon Sep 17 00:00:00 2001 From: David Reid Date: Fri, 2 Apr 2021 09:48:00 +1000 Subject: [PATCH 37/43] Fix a division by 0 when normalizing a vector. --- research/miniaudio_engine.h | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/research/miniaudio_engine.h b/research/miniaudio_engine.h index 85c19a3a..3d54e5fd 100644 --- a/research/miniaudio_engine.h +++ b/research/miniaudio_engine.h @@ -8784,8 +8784,13 @@ MA_API float ma_vec3f_dist(ma_vec3f a, ma_vec3f b) MA_API ma_vec3f ma_vec3f_normalize(ma_vec3f v) { - float f = 1 / ma_vec3f_len(v); - + float f; + float l = ma_vec3f_len(v); + if (l == 0) { + return ma_vec3f_init_3f(0, 0, 0); + } + + f = 1 / l; v.x *= f; v.y *= f; v.z *= f; From 215621f15e8ea238d8ef961a5f6d54bd93b11292 Mon Sep 17 00:00:00 2001 From: David Reid Date: Fri, 2 Apr 2021 10:06:52 +1000 Subject: [PATCH 38/43] Fix an spatialization edge case relating to listener direction. When the listener is looking at exactly the same direction as the world up vector the 3D math breaks down due to a cross product evaluating to a zero length vector. --- research/miniaudio_engine.h | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/research/miniaudio_engine.h b/research/miniaudio_engine.h index 3d54e5fd..d66837e1 100644 --- a/research/miniaudio_engine.h +++ b/research/miniaudio_engine.h @@ -9347,6 +9347,17 @@ MA_API ma_result ma_spatializer_process_pcm_frames(ma_spatializer* pSpatializer, */ axisZ = ma_vec3f_normalize(pListener->direction); /* Normalization required here because we can't trust the caller. */ axisX = ma_vec3f_normalize(ma_vec3f_cross(axisZ, pListener->config.worldUp)); /* Normalization required here because the world up vector may not be perpendicular with the forward vector. */ + + /* + The calculation of axisX above can result in a zero-length vector if the listener is + looking straight up on the Y axis. We'll need to fall back to a +X in this case so that + the calculations below don't fall apart. This is where a quaternion based listener and + sound orientation would come in handy. + */ + if (ma_vec3f_len2(axisX) == 0) { + axisX = ma_vec3f_init_3f(1, 0, 0); + } + axisY = ma_vec3f_cross(axisX, axisZ); /* No normalization is required here because axisX and axisZ are unit length and perpendicular. */ /* From 6d414a359b0a98a2917187a1da7672d7d6c3523f Mon Sep 17 00:00:00 2001 From: David Reid Date: Fri, 2 Apr 2021 10:52:26 +1000 Subject: [PATCH 39/43] An experimental fix for some spatialization issues. --- research/miniaudio_engine.h | 32 +++++++++++++++++++++----------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/research/miniaudio_engine.h b/research/miniaudio_engine.h index d66837e1..bf752d02 100644 --- a/research/miniaudio_engine.h +++ b/research/miniaudio_engine.h @@ -9371,17 +9371,17 @@ MA_API ma_result ma_spatializer_process_pcm_frames(ma_spatializer* pSpatializer, #if 1 { - m[0][0] = axisX.x; m[0][1] = axisY.x; m[0][2] = -axisZ.x; m[0][3] = -ma_vec3f_dot(axisX, pListener->position); - m[1][0] = axisX.y; m[1][1] = axisY.y; m[1][2] = -axisZ.y; m[1][3] = -ma_vec3f_dot(axisY, pListener->position); - m[2][0] = axisX.z; m[2][1] = axisY.z; m[2][2] = -axisZ.z; m[2][3] = -ma_vec3f_dot(axisZ, pListener->position); - m[3][0] = 0; m[3][1] = 0; m[3][2] = 0; m[3][3] = 1; + m[0][0] = axisX.x; m[0][1] = axisY.x; m[0][2] = axisZ.x; m[0][3] = -ma_vec3f_dot(axisX, pListener->position); + m[1][0] = axisX.y; m[1][1] = axisY.y; m[1][2] = axisZ.y; m[1][3] = -ma_vec3f_dot(axisY, pListener->position); + m[2][0] = axisX.z; m[2][1] = axisY.z; m[2][2] = axisZ.z; m[2][3] = -ma_vec3f_dot(axisZ, pListener->position); + m[3][0] = 0; m[3][1] = 0; m[3][2] = 0; m[3][3] = 1; } #else { - m[0][0] = axisX.x; m[1][0] = axisY.x; m[2][0] = -axisZ.x; m[3][0] = -ma_vec3f_dot(axisX, pListener->position); - m[0][1] = axisX.y; m[1][1] = axisY.y; m[2][1] = -axisZ.y; m[3][1] = -ma_vec3f_dot(axisY, pListener->position); - m[0][2] = axisX.z; m[1][2] = axisY.z; m[2][2] = -axisZ.z; m[3][2] = -ma_vec3f_dot(axisZ, pListener->position); - m[0][3] = 0; m[1][3] = 0; m[2][3] = 0; m[3][3] = 1; + m[0][0] = axisX.x; m[1][0] = axisY.x; m[2][0] = axisZ.x; m[3][0] = -ma_vec3f_dot(axisX, pListener->position); + m[0][1] = axisX.y; m[1][1] = axisY.y; m[2][1] = axisZ.y; m[3][1] = -ma_vec3f_dot(axisY, pListener->position); + m[0][2] = axisX.z; m[1][2] = axisY.z; m[2][2] = axisZ.z; m[3][2] = -ma_vec3f_dot(axisZ, pListener->position); + m[0][3] = 0; m[1][3] = 0; m[2][3] = 0; m[3][3] = 1; } #endif @@ -9410,9 +9410,19 @@ MA_API ma_result ma_spatializer_process_pcm_frames(ma_spatializer* pSpatializer, rotation of the listener. */ v = pSpatializer->direction; - relativeDir.x = m[0][0] * v.x + m[1][0] * v.y + m[2][0] * v.z; - relativeDir.y = m[0][1] * v.x + m[1][1] * v.y + m[2][1] * v.z; - relativeDir.z = m[0][2] * v.x + m[1][2] * v.y + m[2][2] * v.z; + #if 0 + { + relativeDir.x = m[0][0] * v.x + m[0][1] * v.y + m[0][2] * v.z; + relativeDir.y = m[1][0] * v.x + m[1][1] * v.y + m[1][2] * v.z; + relativeDir.z = m[2][0] * v.x + m[2][1] * v.y + m[2][2] * v.z; + } + #else + { + relativeDir.x = m[0][0] * v.x + m[1][0] * v.y + m[2][0] * v.z; + relativeDir.y = m[0][1] * v.x + m[1][1] * v.y + m[2][1] * v.z; + relativeDir.z = m[0][2] * v.x + m[1][2] * v.y + m[2][2] * v.z; + } + #endif #if defined(MA_DEBUG_OUTPUT) { From 544ec856f7fb7ed120e6302e30b54af21198a96b Mon Sep 17 00:00:00 2001 From: David Reid Date: Fri, 2 Apr 2021 12:24:19 +1000 Subject: [PATCH 40/43] Another attempt at fixing a spatialization error. --- research/miniaudio_engine.h | 38 ++++++++++++++++++++++++++++--------- 1 file changed, 29 insertions(+), 9 deletions(-) diff --git a/research/miniaudio_engine.h b/research/miniaudio_engine.h index bf752d02..77aede09 100644 --- a/research/miniaudio_engine.h +++ b/research/miniaudio_engine.h @@ -1753,6 +1753,8 @@ MA_API void ma_engine_listener_set_velocity(ma_engine* pEngine, ma_uint32 listen MA_API ma_vec3f ma_engine_listener_get_velocity(const ma_engine* pEngine, ma_uint32 listenerIndex); MA_API void ma_engine_listener_set_cone(ma_engine* pEngine, ma_uint32 listenerIndex, float innerAngleInRadians, float outerAngleInRadians, float outerGain); MA_API void ma_engine_listener_get_cone(const ma_engine* pEngine, ma_uint32 listenerIndex, float* pInnerAngleInRadians, float* pOuterAngleInRadians, float* pOuterGain); +MA_API void ma_engine_listener_set_world_up(ma_engine* pEngine, ma_uint32 listenerIndex, float x, float y, float z); +MA_API ma_vec3f ma_engine_listener_get_world_up(const ma_engine* pEngine, ma_uint32 listenerIndex); MA_API ma_result ma_engine_play_sound(ma_engine* pEngine, const char* pFilePath, ma_sound_group* pGroup); /* Fire and forget. */ @@ -9369,18 +9371,18 @@ MA_API ma_result ma_spatializer_process_pcm_frames(ma_spatializer* pSpatializer, axisX = ma_vec3f_neg(axisX); } - #if 1 + #if 0 { - m[0][0] = axisX.x; m[0][1] = axisY.x; m[0][2] = axisZ.x; m[0][3] = -ma_vec3f_dot(axisX, pListener->position); - m[1][0] = axisX.y; m[1][1] = axisY.y; m[1][2] = axisZ.y; m[1][3] = -ma_vec3f_dot(axisY, pListener->position); - m[2][0] = axisX.z; m[2][1] = axisY.z; m[2][2] = axisZ.z; m[2][3] = -ma_vec3f_dot(axisZ, pListener->position); - m[3][0] = 0; m[3][1] = 0; m[3][2] = 0; m[3][3] = 1; + m[0][0] = axisX.x; m[0][1] = axisY.x; m[0][2] = axisZ.x; m[0][3] = 0; + m[1][0] = axisX.y; m[1][1] = axisY.y; m[1][2] = axisZ.y; m[1][3] = 0; + m[2][0] = axisX.z; m[2][1] = axisY.z; m[2][2] = axisZ.z; m[2][3] = 0; + m[3][0] = -ma_vec3f_dot(axisX, pListener->position); m[3][1] = -ma_vec3f_dot(axisY, pListener->position); m[3][2] = -ma_vec3f_dot(axisZ, pListener->position); m[3][3] = 1; } #else { - m[0][0] = axisX.x; m[1][0] = axisY.x; m[2][0] = axisZ.x; m[3][0] = -ma_vec3f_dot(axisX, pListener->position); - m[0][1] = axisX.y; m[1][1] = axisY.y; m[2][1] = axisZ.y; m[3][1] = -ma_vec3f_dot(axisY, pListener->position); - m[0][2] = axisX.z; m[1][2] = axisY.z; m[2][2] = axisZ.z; m[3][2] = -ma_vec3f_dot(axisZ, pListener->position); + m[0][0] = axisX.x; m[1][0] = axisX.y; m[2][0] = axisX.z; m[3][0] = -ma_vec3f_dot(axisX, pListener->position); + m[0][1] = axisY.x; m[1][1] = axisY.y; m[2][1] = axisY.z; m[3][1] = -ma_vec3f_dot(axisY, pListener->position); + m[0][2] = axisZ.x; m[1][2] = axisZ.y; m[2][2] = axisZ.z; m[3][2] = -ma_vec3f_dot(axisZ, pListener->position); m[0][3] = 0; m[1][3] = 0; m[2][3] = 0; m[3][3] = 1; } #endif @@ -9391,7 +9393,7 @@ MA_API ma_result ma_spatializer_process_pcm_frames(ma_spatializer* pSpatializer, origin which makes things simpler. */ v = pSpatializer->position; - #if 1 + #if 0 { relativePos.x = m[0][0] * v.x + m[0][1] * v.y + m[0][2] * v.z + m[0][3] * 1; relativePos.y = m[1][0] * v.x + m[1][1] * v.y + m[1][2] * v.z + m[1][3] * 1; @@ -10854,6 +10856,24 @@ MA_API void ma_engine_listener_get_cone(const ma_engine* pEngine, ma_uint32 list ma_spatializer_listener_get_cone(&pEngine->listeners[listenerIndex], pInnerAngleInRadians, pOuterAngleInRadians, pOuterGain); } +MA_API void ma_engine_listener_set_world_up(ma_engine* pEngine, ma_uint32 listenerIndex, float x, float y, float z) +{ + if (pEngine == NULL || listenerIndex >= pEngine->listenerCount) { + return; + } + + ma_spatializer_listener_set_world_up(&pEngine->listeners[listenerIndex], x, y, z); +} + +MA_API ma_vec3f ma_engine_listener_get_world_up(const ma_engine* pEngine, ma_uint32 listenerIndex) +{ + if (pEngine == NULL || listenerIndex >= pEngine->listenerCount) { + return ma_vec3f_init_3f(0, 1, 0); + } + + return ma_spatializer_listener_get_world_up(&pEngine->listeners[listenerIndex]); +} + #ifndef MA_NO_RESOURCE_MANAGER MA_API ma_result ma_engine_play_sound_ex(ma_engine* pEngine, const char* pFilePath, ma_node* pNode, ma_uint32 nodeInputBusIndex) From cb983db5351564df69d9e7f873f576946e80948b Mon Sep 17 00:00:00 2001 From: David Reid Date: Fri, 2 Apr 2021 12:39:41 +1000 Subject: [PATCH 41/43] Attempt another fix for reversed front/back spatialization panning. --- research/miniaudio_engine.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/research/miniaudio_engine.h b/research/miniaudio_engine.h index 77aede09..259a4cc2 100644 --- a/research/miniaudio_engine.h +++ b/research/miniaudio_engine.h @@ -9380,10 +9380,10 @@ MA_API ma_result ma_spatializer_process_pcm_frames(ma_spatializer* pSpatializer, } #else { - m[0][0] = axisX.x; m[1][0] = axisX.y; m[2][0] = axisX.z; m[3][0] = -ma_vec3f_dot(axisX, pListener->position); - m[0][1] = axisY.x; m[1][1] = axisY.y; m[2][1] = axisY.z; m[3][1] = -ma_vec3f_dot(axisY, pListener->position); - m[0][2] = axisZ.x; m[1][2] = axisZ.y; m[2][2] = axisZ.z; m[3][2] = -ma_vec3f_dot(axisZ, pListener->position); - m[0][3] = 0; m[1][3] = 0; m[2][3] = 0; m[3][3] = 1; + m[0][0] = axisX.x; m[1][0] = axisX.y; m[2][0] = axisX.z; m[3][0] = -ma_vec3f_dot(axisX, pListener->position); + m[0][1] = axisY.x; m[1][1] = axisY.y; m[2][1] = axisY.z; m[3][1] = -ma_vec3f_dot(axisY, pListener->position); + m[0][2] = -axisZ.x; m[1][2] = -axisZ.y; m[2][2] = -axisZ.z; m[3][2] = -ma_vec3f_dot(ma_vec3f_neg(axisZ), pListener->position); + m[0][3] = 0; m[1][3] = 0; m[2][3] = 0; m[3][3] = 1; } #endif From f814a10c0236437b240c21f76faf4a0180ece197 Mon Sep 17 00:00:00 2001 From: David Reid Date: Fri, 2 Apr 2021 13:50:16 +1000 Subject: [PATCH 42/43] Try fixing a bug with doppler effect and rotations. --- research/miniaudio_engine.h | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/research/miniaudio_engine.h b/research/miniaudio_engine.h index 259a4cc2..3972c38f 100644 --- a/research/miniaudio_engine.h +++ b/research/miniaudio_engine.h @@ -9630,10 +9630,16 @@ MA_API ma_result ma_spatializer_process_pcm_frames(ma_spatializer* pSpatializer, source. */ if (pSpatializer->config.dopplerFactor > 0) { - pSpatializer->dopplerPitch = ma_doppler_pitch(ma_vec3f_neg(relativePos), pSpatializer->velocity, listenerVel, speedOfSound, pSpatializer->config.dopplerFactor); + pSpatializer->dopplerPitch = ma_doppler_pitch(ma_vec3f_sub(pListener->position, pSpatializer->position), pSpatializer->velocity, listenerVel, speedOfSound, pSpatializer->config.dopplerFactor); } else { pSpatializer->dopplerPitch = 1; } + + #if defined(MA_DEBUG_OUTPUT) + { + /*printf("dopplerPitch = %f; relativePos = {%f %f %f}\n", pSpatializer->dopplerPitch, relativePos.x, relativePos.y, relativePos.z);*/ + } + #endif } return MA_SUCCESS; From fca829edefd8389380f8e3ee26cc4b8c426dd742 Mon Sep 17 00:00:00 2001 From: David Reid Date: Sun, 4 Apr 2021 08:04:50 +1000 Subject: [PATCH 43/43] Version 0.10.33 --- extras/miniaudio_split/miniaudio.c | 283 +++++++++++++++++++---------- extras/miniaudio_split/miniaudio.h | 6 +- miniaudio.h | 5 +- 3 files changed, 198 insertions(+), 96 deletions(-) diff --git a/extras/miniaudio_split/miniaudio.c b/extras/miniaudio_split/miniaudio.c index e0bc4723..0765157c 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.32 - 2020-02-23 +miniaudio - v0.10.33 - 2021-04-04 David Reid - mackron@gmail.com @@ -391,22 +391,45 @@ static MA_INLINE ma_bool32 ma_has_neon(void) #endif #endif +#if defined(__has_builtin) + #define MA_COMPILER_HAS_BUILTIN(x) __has_builtin(x) +#else + #define MA_COMPILER_HAS_BUILTIN(x) 0 +#endif + +#ifndef MA_ASSUME + #if MA_COMPILER_HAS_BUILTIN(__builtin_assume) + #define MA_ASSUME(x) __builtin_assume(x) + #elif MA_COMPILER_HAS_BUILTIN(__builtin_unreachable) + #define MA_ASSUME(x) do { if (!(x)) __builtin_unreachable(); } while (0) + #elif defined(_MSC_VER) + #define MA_ASSUME(x) __assume(x) + #else + #define MA_ASSUME(x) while(0) + #endif +#endif + +#ifndef MA_RESTRICT + #if defined(__clang__) || defined(__GNUC__) || defined(_MSC_VER) + #define MA_RESTRICT __restrict + #else + #define MA_RESTRICT + #endif +#endif #if defined(_MSC_VER) && _MSC_VER >= 1400 #define MA_HAS_BYTESWAP16_INTRINSIC #define MA_HAS_BYTESWAP32_INTRINSIC #define MA_HAS_BYTESWAP64_INTRINSIC #elif defined(__clang__) - #if defined(__has_builtin) - #if __has_builtin(__builtin_bswap16) - #define MA_HAS_BYTESWAP16_INTRINSIC - #endif - #if __has_builtin(__builtin_bswap32) - #define MA_HAS_BYTESWAP32_INTRINSIC - #endif - #if __has_builtin(__builtin_bswap64) - #define MA_HAS_BYTESWAP64_INTRINSIC - #endif + #if MA_COMPILER_HAS_BUILTIN(__builtin_bswap16) + #define MA_HAS_BYTESWAP16_INTRINSIC + #endif + #if MA_COMPILER_HAS_BUILTIN(__builtin_bswap32) + #define MA_HAS_BYTESWAP32_INTRINSIC + #endif + #if MA_COMPILER_HAS_BUILTIN(__builtin_bswap64) + #define MA_HAS_BYTESWAP64_INTRINSIC #endif #elif defined(__GNUC__) #if ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)) @@ -2377,31 +2400,31 @@ typedef unsigned char c89atomic_bool; #define c89atomic_compiler_fence() c89atomic_thread_fence(c89atomic_memory_order_seq_cst) #define c89atomic_signal_fence(order) c89atomic_thread_fence(order) #if defined(C89ATOMIC_HAS_8) - static C89ATOMIC_INLINE c89atomic_uint8 c89atomic_load_explicit_8(volatile c89atomic_uint8* ptr, c89atomic_memory_order order) + static C89ATOMIC_INLINE c89atomic_uint8 c89atomic_load_explicit_8(volatile const c89atomic_uint8* ptr, c89atomic_memory_order order) { (void)order; - return c89atomic_compare_and_swap_8(ptr, 0, 0); + return c89atomic_compare_and_swap_8((c89atomic_uint8*)ptr, 0, 0); } #endif #if defined(C89ATOMIC_HAS_16) - static C89ATOMIC_INLINE c89atomic_uint16 c89atomic_load_explicit_16(volatile c89atomic_uint16* ptr, c89atomic_memory_order order) + static C89ATOMIC_INLINE c89atomic_uint16 c89atomic_load_explicit_16(volatile const c89atomic_uint16* ptr, c89atomic_memory_order order) { (void)order; - return c89atomic_compare_and_swap_16(ptr, 0, 0); + return c89atomic_compare_and_swap_16((c89atomic_uint16*)ptr, 0, 0); } #endif #if defined(C89ATOMIC_HAS_32) - static C89ATOMIC_INLINE c89atomic_uint32 c89atomic_load_explicit_32(volatile c89atomic_uint32* ptr, c89atomic_memory_order order) + static C89ATOMIC_INLINE c89atomic_uint32 c89atomic_load_explicit_32(volatile const c89atomic_uint32* ptr, c89atomic_memory_order order) { (void)order; - return c89atomic_compare_and_swap_32(ptr, 0, 0); + return c89atomic_compare_and_swap_32((c89atomic_uint32*)ptr, 0, 0); } #endif #if defined(C89ATOMIC_HAS_64) - static C89ATOMIC_INLINE c89atomic_uint64 c89atomic_load_explicit_64(volatile c89atomic_uint64* ptr, c89atomic_memory_order order) + static C89ATOMIC_INLINE c89atomic_uint64 c89atomic_load_explicit_64(volatile const c89atomic_uint64* ptr, c89atomic_memory_order order) { (void)order; - return c89atomic_compare_and_swap_64(ptr, 0, 0); + return c89atomic_compare_and_swap_64((c89atomic_uint64*)ptr, 0, 0); } #endif #if defined(C89ATOMIC_HAS_8) @@ -3209,25 +3232,25 @@ typedef unsigned char c89atomic_bool; } #endif #define c89atomic_signal_fence(order) c89atomic_thread_fence(order) - static C89ATOMIC_INLINE c89atomic_uint8 c89atomic_load_explicit_8(volatile c89atomic_uint8* ptr, c89atomic_memory_order order) + static C89ATOMIC_INLINE c89atomic_uint8 c89atomic_load_explicit_8(volatile const c89atomic_uint8* ptr, c89atomic_memory_order order) { (void)order; - return c89atomic_compare_and_swap_8(ptr, 0, 0); + return c89atomic_compare_and_swap_8((c89atomic_uint8*)ptr, 0, 0); } - static C89ATOMIC_INLINE c89atomic_uint16 c89atomic_load_explicit_16(volatile c89atomic_uint16* ptr, c89atomic_memory_order order) + static C89ATOMIC_INLINE c89atomic_uint16 c89atomic_load_explicit_16(volatile const c89atomic_uint16* ptr, c89atomic_memory_order order) { (void)order; - return c89atomic_compare_and_swap_16(ptr, 0, 0); + return c89atomic_compare_and_swap_16((c89atomic_uint16*)ptr, 0, 0); } - static C89ATOMIC_INLINE c89atomic_uint32 c89atomic_load_explicit_32(volatile c89atomic_uint32* ptr, c89atomic_memory_order order) + static C89ATOMIC_INLINE c89atomic_uint32 c89atomic_load_explicit_32(volatile const c89atomic_uint32* ptr, c89atomic_memory_order order) { (void)order; - return c89atomic_compare_and_swap_32(ptr, 0, 0); + return c89atomic_compare_and_swap_32((c89atomic_uint32*)ptr, 0, 0); } - static C89ATOMIC_INLINE c89atomic_uint64 c89atomic_load_explicit_64(volatile c89atomic_uint64* ptr, c89atomic_memory_order order) + static C89ATOMIC_INLINE c89atomic_uint64 c89atomic_load_explicit_64(volatile const c89atomic_uint64* ptr, c89atomic_memory_order order) { (void)order; - return c89atomic_compare_and_swap_64(ptr, 0, 0); + return c89atomic_compare_and_swap_64((c89atomic_uint64*)ptr, 0, 0); } #define c89atomic_store_explicit_8( dst, src, order) (void)c89atomic_exchange_explicit_8 (dst, src, order) #define c89atomic_store_explicit_16(dst, src, order) (void)c89atomic_exchange_explicit_16(dst, src, order) @@ -9914,6 +9937,8 @@ static ma_result ma_context_init__wasapi(ma_context* pContext, const ma_context_ return result; } + MA_ZERO_OBJECT(&pContext->wasapi); + /* Annoyingly, WASAPI does not allow you to release an IAudioClient object from a different thread than the one that retrieved it with GetService(). This can result in a deadlock in two @@ -16168,9 +16193,9 @@ static ma_result ma_device_init__pulse(ma_device* pDevice, const ma_device_confi int error = 0; const char* devPlayback = NULL; const char* devCapture = NULL; - ma_format format; - ma_uint32 channels; - ma_uint32 sampleRate; + ma_format format = ma_format_unknown; + ma_uint32 channels = 0; + ma_uint32 sampleRate = 0; ma_pa_sink_info sinkInfo; ma_pa_source_info sourceInfo; ma_pa_sample_spec ss; @@ -16549,7 +16574,7 @@ static ma_result ma_device_data_loop__pulse(ma_device* pDevice) /* NOTE: Don't start the device here. It'll be done at a higher level. */ /* - Are data is handled through callbacks. All we need to do is iterate over the main loop and let + All data is handled through callbacks. All we need to do is iterate over the main loop and let the callbacks deal with it. */ while (ma_device_get_state(pDevice) == MA_STATE_STARTED) { @@ -17365,7 +17390,8 @@ static ma_result ma_context_init__jack(ma_context* pContext, const ma_context_co #ifndef MA_NO_RUNTIME_LINKING const char* libjackNames[] = { #ifdef MA_WIN32 - "libjack.dll" + "libjack.dll", + "libjack64.dll" #else "libjack.so", "libjack.so.0" @@ -18881,6 +18907,8 @@ static ma_result ma_context_get_device_info__coreaudio(ma_context* pContext, ma_ } } + ma_free(pSampleRateRanges, &pContext->allocationCallbacks); + if (pDeviceInfo->nativeDataFormatCount >= ma_countof(pDeviceInfo->nativeDataFormats)) { break; /* No more room for any more formats. */ } @@ -20310,7 +20338,7 @@ static ma_result ma_device_init__coreaudio(ma_device* pDevice, const ma_device_c data.sampleRateIn = pDescriptorPlayback->sampleRate; MA_COPY_MEMORY(data.channelMapIn, pDescriptorPlayback->channelMap, sizeof(pDescriptorPlayback->channelMap)); data.shareMode = pDescriptorPlayback->shareMode; - data.shareMode = pDescriptorPlayback->shareMode; + data.performanceProfile = pConfig->performanceProfile; /* In full-duplex mode we want the playback buffer to be the same size as the capture buffer. */ if (pConfig->deviceType == ma_device_type_duplex) { @@ -27200,12 +27228,22 @@ MA_API ma_uint32 ma_scale_buffer_size(ma_uint32 baseBufferSize, float scale) MA_API ma_uint32 ma_calculate_buffer_size_in_milliseconds_from_frames(ma_uint32 bufferSizeInFrames, ma_uint32 sampleRate) { - return bufferSizeInFrames / (sampleRate/1000); + /* Prevent a division by zero. */ + if (sampleRate == 0) { + return 0; + } + + return bufferSizeInFrames*1000 / sampleRate; } MA_API ma_uint32 ma_calculate_buffer_size_in_frames_from_milliseconds(ma_uint32 bufferSizeInMilliseconds, ma_uint32 sampleRate) { - return bufferSizeInMilliseconds * (sampleRate/1000); + /* Prevent a division by zero. */ + if (sampleRate == 0) { + return 0; + } + + return bufferSizeInMilliseconds*sampleRate / 1000; } MA_API void ma_copy_pcm_frames(void* dst, const void* src, ma_uint64 frameCount, ma_format format, ma_uint32 channels) @@ -29937,13 +29975,15 @@ MA_API ma_result ma_biquad_reinit(const ma_biquad_config* pConfig, ma_biquad* pB static MA_INLINE void ma_biquad_process_pcm_frame_f32__direct_form_2_transposed(ma_biquad* pBQ, float* pY, const float* pX) { ma_uint32 c; + const ma_uint32 channels = pBQ->channels; const float b0 = pBQ->b0.f32; const float b1 = pBQ->b1.f32; const float b2 = pBQ->b2.f32; const float a1 = pBQ->a1.f32; const float a2 = pBQ->a2.f32; - for (c = 0; c < pBQ->channels; c += 1) { + MA_ASSUME(channels >= MA_MIN_CHANNELS && channels <= MA_MAX_CHANNELS); + for (c = 0; c < channels; c += 1) { float r1 = pBQ->r1[c].f32; float r2 = pBQ->r2[c].f32; float x = pX[c]; @@ -29967,13 +30007,15 @@ static MA_INLINE void ma_biquad_process_pcm_frame_f32(ma_biquad* pBQ, float* pY, static MA_INLINE void ma_biquad_process_pcm_frame_s16__direct_form_2_transposed(ma_biquad* pBQ, ma_int16* pY, const ma_int16* pX) { ma_uint32 c; + const ma_uint32 channels = pBQ->channels; const ma_int32 b0 = pBQ->b0.s32; const ma_int32 b1 = pBQ->b1.s32; const ma_int32 b2 = pBQ->b2.s32; const ma_int32 a1 = pBQ->a1.s32; const ma_int32 a2 = pBQ->a2.s32; - for (c = 0; c < pBQ->channels; c += 1) { + MA_ASSUME(channels >= MA_MIN_CHANNELS && channels <= MA_MAX_CHANNELS); + for (c = 0; c < channels; c += 1) { ma_int32 r1 = pBQ->r1[c].s32; ma_int32 r2 = pBQ->r2[c].s32; ma_int32 x = pX[c]; @@ -30137,10 +30179,12 @@ MA_API ma_result ma_lpf1_reinit(const ma_lpf1_config* pConfig, ma_lpf1* pLPF) static MA_INLINE void ma_lpf1_process_pcm_frame_f32(ma_lpf1* pLPF, float* pY, const float* pX) { ma_uint32 c; + const ma_uint32 channels = pLPF->channels; const float a = pLPF->a.f32; const float b = 1 - a; - for (c = 0; c < pLPF->channels; c += 1) { + MA_ASSUME(channels >= MA_MIN_CHANNELS && channels <= MA_MAX_CHANNELS); + for (c = 0; c < channels; c += 1) { float r1 = pLPF->r1[c].f32; float x = pX[c]; float y; @@ -30155,10 +30199,12 @@ static MA_INLINE void ma_lpf1_process_pcm_frame_f32(ma_lpf1* pLPF, float* pY, co static MA_INLINE void ma_lpf1_process_pcm_frame_s16(ma_lpf1* pLPF, ma_int16* pY, const ma_int16* pX) { ma_uint32 c; + const ma_uint32 channels = pLPF->channels; const ma_int32 a = pLPF->a.s32; const ma_int32 b = ((1 << MA_BIQUAD_FIXED_POINT_SHIFT) - a); - for (c = 0; c < pLPF->channels; c += 1) { + MA_ASSUME(channels >= MA_MIN_CHANNELS && channels <= MA_MAX_CHANNELS); + for (c = 0; c < channels; c += 1) { ma_int32 r1 = pLPF->r1[c].s32; ma_int32 x = pX[c]; ma_int32 y; @@ -30644,10 +30690,12 @@ MA_API ma_result ma_hpf1_reinit(const ma_hpf1_config* pConfig, ma_hpf1* pHPF) static MA_INLINE void ma_hpf1_process_pcm_frame_f32(ma_hpf1* pHPF, float* pY, const float* pX) { ma_uint32 c; + const ma_uint32 channels = pHPF->channels; const float a = 1 - pHPF->a.f32; const float b = 1 - a; - for (c = 0; c < pHPF->channels; c += 1) { + MA_ASSUME(channels >= MA_MIN_CHANNELS && channels <= MA_MAX_CHANNELS); + for (c = 0; c < channels; c += 1) { float r1 = pHPF->r1[c].f32; float x = pX[c]; float y; @@ -30662,10 +30710,12 @@ static MA_INLINE void ma_hpf1_process_pcm_frame_f32(ma_hpf1* pHPF, float* pY, co static MA_INLINE void ma_hpf1_process_pcm_frame_s16(ma_hpf1* pHPF, ma_int16* pY, const ma_int16* pX) { ma_uint32 c; + const ma_uint32 channels = pHPF->channels; const ma_int32 a = ((1 << MA_BIQUAD_FIXED_POINT_SHIFT) - pHPF->a.s32); const ma_int32 b = ((1 << MA_BIQUAD_FIXED_POINT_SHIFT) - a); - for (c = 0; c < pHPF->channels; c += 1) { + MA_ASSUME(channels >= MA_MIN_CHANNELS && channels <= MA_MAX_CHANNELS); + for (c = 0; c < channels; c += 1) { ma_int32 r1 = pHPF->r1[c].s32; ma_int32 x = pX[c]; ma_int32 y; @@ -31998,10 +32048,11 @@ static MA_INLINE ma_int16 ma_linear_resampler_mix_s16(ma_int16 x, ma_int16 y, ma return (ma_int16)(r >> shift); } -static void ma_linear_resampler_interpolate_frame_s16(ma_linear_resampler* pResampler, ma_int16* pFrameOut) +static void ma_linear_resampler_interpolate_frame_s16(ma_linear_resampler* pResampler, ma_int16* MA_RESTRICT pFrameOut) { ma_uint32 c; ma_uint32 a; + const ma_uint32 channels = pResampler->config.channels; const ma_uint32 shift = 12; MA_ASSERT(pResampler != NULL); @@ -32009,24 +32060,27 @@ static void ma_linear_resampler_interpolate_frame_s16(ma_linear_resampler* pResa a = (pResampler->inTimeFrac << shift) / pResampler->config.sampleRateOut; - for (c = 0; c < pResampler->config.channels; c += 1) { + MA_ASSUME(channels >= MA_MIN_CHANNELS && channels <= MA_MAX_CHANNELS); + for (c = 0; c < channels; c += 1) { ma_int16 s = ma_linear_resampler_mix_s16(pResampler->x0.s16[c], pResampler->x1.s16[c], a, shift); pFrameOut[c] = s; } } -static void ma_linear_resampler_interpolate_frame_f32(ma_linear_resampler* pResampler, float* pFrameOut) +static void ma_linear_resampler_interpolate_frame_f32(ma_linear_resampler* pResampler, float* MA_RESTRICT pFrameOut) { ma_uint32 c; float a; + const ma_uint32 channels = pResampler->config.channels; MA_ASSERT(pResampler != NULL); MA_ASSERT(pFrameOut != NULL); a = (float)pResampler->inTimeFrac / pResampler->config.sampleRateOut; - for (c = 0; c < pResampler->config.channels; c += 1) { + MA_ASSUME(channels >= MA_MIN_CHANNELS && channels <= MA_MAX_CHANNELS); + for (c = 0; c < channels; c += 1) { float s = ma_mix_f32_fast(pResampler->x0.f32[c], pResampler->x1.f32[c], a); pFrameOut[c] = s; } @@ -38435,7 +38489,7 @@ extern "C" { #define DRFLAC_XSTRINGIFY(x) DRFLAC_STRINGIFY(x) #define DRFLAC_VERSION_MAJOR 0 #define DRFLAC_VERSION_MINOR 12 -#define DRFLAC_VERSION_REVISION 28 +#define DRFLAC_VERSION_REVISION 29 #define DRFLAC_VERSION_STRING DRFLAC_XSTRINGIFY(DRFLAC_VERSION_MAJOR) "." DRFLAC_XSTRINGIFY(DRFLAC_VERSION_MINOR) "." DRFLAC_XSTRINGIFY(DRFLAC_VERSION_REVISION) #include typedef signed char drflac_int8; @@ -42334,20 +42388,22 @@ static MA_INLINE ma_uint64 ma_noise_read_pcm_frames__white(ma_noise* pNoise, voi { ma_uint64 iFrame; ma_uint32 iChannel; + const ma_uint32 channels = pNoise->config.channels; + MA_ASSUME(channels >= MA_MIN_CHANNELS && channels <= MA_MAX_CHANNELS); if (pNoise->config.format == ma_format_f32) { float* pFramesOutF32 = (float*)pFramesOut; if (pNoise->config.duplicateChannels) { for (iFrame = 0; iFrame < frameCount; iFrame += 1) { float s = ma_noise_f32_white(pNoise); - for (iChannel = 0; iChannel < pNoise->config.channels; iChannel += 1) { - pFramesOutF32[iFrame*pNoise->config.channels + iChannel] = s; + for (iChannel = 0; iChannel < channels; iChannel += 1) { + pFramesOutF32[iFrame*channels + iChannel] = s; } } } else { for (iFrame = 0; iFrame < frameCount; iFrame += 1) { - for (iChannel = 0; iChannel < pNoise->config.channels; iChannel += 1) { - pFramesOutF32[iFrame*pNoise->config.channels + iChannel] = ma_noise_f32_white(pNoise); + for (iChannel = 0; iChannel < channels; iChannel += 1) { + pFramesOutF32[iFrame*channels + iChannel] = ma_noise_f32_white(pNoise); } } } @@ -42356,31 +42412,31 @@ static MA_INLINE ma_uint64 ma_noise_read_pcm_frames__white(ma_noise* pNoise, voi if (pNoise->config.duplicateChannels) { for (iFrame = 0; iFrame < frameCount; iFrame += 1) { ma_int16 s = ma_noise_s16_white(pNoise); - for (iChannel = 0; iChannel < pNoise->config.channels; iChannel += 1) { - pFramesOutS16[iFrame*pNoise->config.channels + iChannel] = s; + for (iChannel = 0; iChannel < channels; iChannel += 1) { + pFramesOutS16[iFrame*channels + iChannel] = s; } } } else { for (iFrame = 0; iFrame < frameCount; iFrame += 1) { - for (iChannel = 0; iChannel < pNoise->config.channels; iChannel += 1) { - pFramesOutS16[iFrame*pNoise->config.channels + iChannel] = ma_noise_s16_white(pNoise); + for (iChannel = 0; iChannel < channels; iChannel += 1) { + pFramesOutS16[iFrame*channels + iChannel] = ma_noise_s16_white(pNoise); } } } } else { - ma_uint32 bps = ma_get_bytes_per_sample(pNoise->config.format); - ma_uint32 bpf = bps * pNoise->config.channels; + const ma_uint32 bps = ma_get_bytes_per_sample(pNoise->config.format); + const ma_uint32 bpf = bps * channels; if (pNoise->config.duplicateChannels) { for (iFrame = 0; iFrame < frameCount; iFrame += 1) { float s = ma_noise_f32_white(pNoise); - for (iChannel = 0; iChannel < pNoise->config.channels; iChannel += 1) { + for (iChannel = 0; iChannel < channels; iChannel += 1) { ma_pcm_convert(ma_offset_ptr(pFramesOut, iFrame*bpf + iChannel*bps), pNoise->config.format, &s, ma_format_f32, 1, ma_dither_mode_none); } } } else { for (iFrame = 0; iFrame < frameCount; iFrame += 1) { - for (iChannel = 0; iChannel < pNoise->config.channels; iChannel += 1) { + for (iChannel = 0; iChannel < channels; iChannel += 1) { float s = ma_noise_f32_white(pNoise); ma_pcm_convert(ma_offset_ptr(pFramesOut, iFrame*bpf + iChannel*bps), pNoise->config.format, &s, ma_format_f32, 1, ma_dither_mode_none); } @@ -42451,20 +42507,22 @@ static MA_INLINE ma_uint64 ma_noise_read_pcm_frames__pink(ma_noise* pNoise, void { ma_uint64 iFrame; ma_uint32 iChannel; + const ma_uint32 channels = pNoise->config.channels; + MA_ASSUME(channels >= MA_MIN_CHANNELS && channels <= MA_MAX_CHANNELS); if (pNoise->config.format == ma_format_f32) { float* pFramesOutF32 = (float*)pFramesOut; if (pNoise->config.duplicateChannels) { for (iFrame = 0; iFrame < frameCount; iFrame += 1) { float s = ma_noise_f32_pink(pNoise, 0); - for (iChannel = 0; iChannel < pNoise->config.channels; iChannel += 1) { - pFramesOutF32[iFrame*pNoise->config.channels + iChannel] = s; + for (iChannel = 0; iChannel < channels; iChannel += 1) { + pFramesOutF32[iFrame*channels + iChannel] = s; } } } else { for (iFrame = 0; iFrame < frameCount; iFrame += 1) { - for (iChannel = 0; iChannel < pNoise->config.channels; iChannel += 1) { - pFramesOutF32[iFrame*pNoise->config.channels + iChannel] = ma_noise_f32_pink(pNoise, iChannel); + for (iChannel = 0; iChannel < channels; iChannel += 1) { + pFramesOutF32[iFrame*channels + iChannel] = ma_noise_f32_pink(pNoise, iChannel); } } } @@ -42473,31 +42531,31 @@ static MA_INLINE ma_uint64 ma_noise_read_pcm_frames__pink(ma_noise* pNoise, void if (pNoise->config.duplicateChannels) { for (iFrame = 0; iFrame < frameCount; iFrame += 1) { ma_int16 s = ma_noise_s16_pink(pNoise, 0); - for (iChannel = 0; iChannel < pNoise->config.channels; iChannel += 1) { - pFramesOutS16[iFrame*pNoise->config.channels + iChannel] = s; + for (iChannel = 0; iChannel < channels; iChannel += 1) { + pFramesOutS16[iFrame*channels + iChannel] = s; } } } else { for (iFrame = 0; iFrame < frameCount; iFrame += 1) { - for (iChannel = 0; iChannel < pNoise->config.channels; iChannel += 1) { - pFramesOutS16[iFrame*pNoise->config.channels + iChannel] = ma_noise_s16_pink(pNoise, iChannel); + for (iChannel = 0; iChannel < channels; iChannel += 1) { + pFramesOutS16[iFrame*channels + iChannel] = ma_noise_s16_pink(pNoise, iChannel); } } } } else { - ma_uint32 bps = ma_get_bytes_per_sample(pNoise->config.format); - ma_uint32 bpf = bps * pNoise->config.channels; + const ma_uint32 bps = ma_get_bytes_per_sample(pNoise->config.format); + const ma_uint32 bpf = bps * channels; if (pNoise->config.duplicateChannels) { for (iFrame = 0; iFrame < frameCount; iFrame += 1) { float s = ma_noise_f32_pink(pNoise, 0); - for (iChannel = 0; iChannel < pNoise->config.channels; iChannel += 1) { + for (iChannel = 0; iChannel < channels; iChannel += 1) { ma_pcm_convert(ma_offset_ptr(pFramesOut, iFrame*bpf + iChannel*bps), pNoise->config.format, &s, ma_format_f32, 1, ma_dither_mode_none); } } } else { for (iFrame = 0; iFrame < frameCount; iFrame += 1) { - for (iChannel = 0; iChannel < pNoise->config.channels; iChannel += 1) { + for (iChannel = 0; iChannel < channels; iChannel += 1) { float s = ma_noise_f32_pink(pNoise, iChannel); ma_pcm_convert(ma_offset_ptr(pFramesOut, iFrame*bpf + iChannel*bps), pNoise->config.format, &s, ma_format_f32, 1, ma_dither_mode_none); } @@ -42531,20 +42589,22 @@ static MA_INLINE ma_uint64 ma_noise_read_pcm_frames__brownian(ma_noise* pNoise, { ma_uint64 iFrame; ma_uint32 iChannel; + const ma_uint32 channels = pNoise->config.channels; + MA_ASSUME(channels >= MA_MIN_CHANNELS && channels <= MA_MAX_CHANNELS); if (pNoise->config.format == ma_format_f32) { float* pFramesOutF32 = (float*)pFramesOut; if (pNoise->config.duplicateChannels) { for (iFrame = 0; iFrame < frameCount; iFrame += 1) { float s = ma_noise_f32_brownian(pNoise, 0); - for (iChannel = 0; iChannel < pNoise->config.channels; iChannel += 1) { - pFramesOutF32[iFrame*pNoise->config.channels + iChannel] = s; + for (iChannel = 0; iChannel < channels; iChannel += 1) { + pFramesOutF32[iFrame*channels + iChannel] = s; } } } else { for (iFrame = 0; iFrame < frameCount; iFrame += 1) { - for (iChannel = 0; iChannel < pNoise->config.channels; iChannel += 1) { - pFramesOutF32[iFrame*pNoise->config.channels + iChannel] = ma_noise_f32_brownian(pNoise, iChannel); + for (iChannel = 0; iChannel < channels; iChannel += 1) { + pFramesOutF32[iFrame*channels + iChannel] = ma_noise_f32_brownian(pNoise, iChannel); } } } @@ -42553,31 +42613,31 @@ static MA_INLINE ma_uint64 ma_noise_read_pcm_frames__brownian(ma_noise* pNoise, if (pNoise->config.duplicateChannels) { for (iFrame = 0; iFrame < frameCount; iFrame += 1) { ma_int16 s = ma_noise_s16_brownian(pNoise, 0); - for (iChannel = 0; iChannel < pNoise->config.channels; iChannel += 1) { - pFramesOutS16[iFrame*pNoise->config.channels + iChannel] = s; + for (iChannel = 0; iChannel < channels; iChannel += 1) { + pFramesOutS16[iFrame*channels + iChannel] = s; } } } else { for (iFrame = 0; iFrame < frameCount; iFrame += 1) { - for (iChannel = 0; iChannel < pNoise->config.channels; iChannel += 1) { - pFramesOutS16[iFrame*pNoise->config.channels + iChannel] = ma_noise_s16_brownian(pNoise, iChannel); + for (iChannel = 0; iChannel < channels; iChannel += 1) { + pFramesOutS16[iFrame*channels + iChannel] = ma_noise_s16_brownian(pNoise, iChannel); } } } } else { - ma_uint32 bps = ma_get_bytes_per_sample(pNoise->config.format); - ma_uint32 bpf = bps * pNoise->config.channels; + const ma_uint32 bps = ma_get_bytes_per_sample(pNoise->config.format); + const ma_uint32 bpf = bps * channels; if (pNoise->config.duplicateChannels) { for (iFrame = 0; iFrame < frameCount; iFrame += 1) { float s = ma_noise_f32_brownian(pNoise, 0); - for (iChannel = 0; iChannel < pNoise->config.channels; iChannel += 1) { + for (iChannel = 0; iChannel < channels; iChannel += 1) { ma_pcm_convert(ma_offset_ptr(pFramesOut, iFrame*bpf + iChannel*bps), pNoise->config.format, &s, ma_format_f32, 1, ma_dither_mode_none); } } } else { for (iFrame = 0; iFrame < frameCount; iFrame += 1) { - for (iChannel = 0; iChannel < pNoise->config.channels; iChannel += 1) { + for (iChannel = 0; iChannel < channels; iChannel += 1) { float s = ma_noise_f32_brownian(pNoise, iChannel); ma_pcm_convert(ma_offset_ptr(pFramesOut, iFrame*bpf + iChannel*bps), pNoise->config.format, &s, ma_format_f32, 1, ma_dither_mode_none); } @@ -46603,6 +46663,27 @@ static DRFLAC_INLINE drflac_bool32 drflac_has_sse41(void) #if ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)) #define DRFLAC_HAS_BYTESWAP16_INTRINSIC #endif +#elif defined(__WATCOMC__) && defined(__386__) + #define DRFLAC_HAS_BYTESWAP16_INTRINSIC + #define DRFLAC_HAS_BYTESWAP32_INTRINSIC + #define DRFLAC_HAS_BYTESWAP64_INTRINSIC + extern __inline drflac_uint16 _watcom_bswap16(drflac_uint16); + extern __inline drflac_uint32 _watcom_bswap32(drflac_uint32); + extern __inline drflac_uint64 _watcom_bswap64(drflac_uint64); +#pragma aux _watcom_bswap16 = \ + "xchg al, ah" \ + parm [ax] \ + modify [ax]; +#pragma aux _watcom_bswap32 = \ + "bswap eax" \ + parm [eax] \ + modify [eax]; +#pragma aux _watcom_bswap64 = \ + "bswap eax" \ + "bswap edx" \ + "xchg eax,edx" \ + parm [eax edx] \ + modify [eax edx]; #endif #ifndef DRFLAC_ASSERT #include @@ -46784,6 +46865,8 @@ static DRFLAC_INLINE drflac_uint16 drflac__swap_endian_uint16(drflac_uint16 n) return _byteswap_ushort(n); #elif defined(__GNUC__) || defined(__clang__) return __builtin_bswap16(n); + #elif defined(__WATCOMC__) && defined(__386__) + return _watcom_bswap16(n); #else #error "This compiler does not support the byte swap intrinsic." #endif @@ -46811,6 +46894,8 @@ static DRFLAC_INLINE drflac_uint32 drflac__swap_endian_uint32(drflac_uint32 n) #else return __builtin_bswap32(n); #endif + #elif defined(__WATCOMC__) && defined(__386__) + return _watcom_bswap32(n); #else #error "This compiler does not support the byte swap intrinsic." #endif @@ -46828,6 +46913,8 @@ static DRFLAC_INLINE drflac_uint64 drflac__swap_endian_uint64(drflac_uint64 n) return _byteswap_uint64(n); #elif defined(__GNUC__) || defined(__clang__) return __builtin_bswap64(n); + #elif defined(__WATCOMC__) && defined(__386__) + return _watcom_bswap64(n); #else #error "This compiler does not support the byte swap intrinsic." #endif @@ -47445,6 +47532,9 @@ static drflac_bool32 drflac__find_and_seek_to_next_sync_code(drflac_bs* bs) #if defined(_MSC_VER) && _MSC_VER >= 1400 && (defined(DRFLAC_X64) || defined(DRFLAC_X86)) && !defined(__clang__) #define DRFLAC_IMPLEMENT_CLZ_MSVC #endif +#if defined(__WATCOMC__) && defined(__386__) +#define DRFLAC_IMPLEMENT_CLZ_WATCOM +#endif static DRFLAC_INLINE drflac_uint32 drflac__clz_software(drflac_cache_t x) { drflac_uint32 n; @@ -47557,6 +47647,15 @@ static DRFLAC_INLINE drflac_uint32 drflac__clz_msvc(drflac_cache_t x) return sizeof(x)*8 - n - 1; } #endif +#ifdef DRFLAC_IMPLEMENT_CLZ_WATCOM +static __inline drflac_uint32 drflac__clz_watcom (drflac_uint32); +#pragma aux drflac__clz_watcom = \ + "bsr eax, eax" \ + "xor eax, 31" \ + parm [eax] nomemory \ + value [eax] \ + modify exact [eax] nomemory; +#endif static DRFLAC_INLINE drflac_uint32 drflac__clz(drflac_cache_t x) { #ifdef DRFLAC_IMPLEMENT_CLZ_LZCNT @@ -47567,6 +47666,8 @@ static DRFLAC_INLINE drflac_uint32 drflac__clz(drflac_cache_t x) { #ifdef DRFLAC_IMPLEMENT_CLZ_MSVC return drflac__clz_msvc(x); +#elif defined(DRFLAC_IMPLEMENT_CLZ_WATCOM) + return (x == 0) ? sizeof(x)*8 : drflac__clz_watcom(x); #else return drflac__clz_software(x); #endif @@ -47883,7 +47984,6 @@ static drflac_bool32 drflac__decode_samples_with_residual__rice__reference(drfla { drflac_uint32 i; DRFLAC_ASSERT(bs != NULL); - DRFLAC_ASSERT(count > 0); DRFLAC_ASSERT(pSamplesOut != NULL); for (i = 0; i < count; ++i) { drflac_uint32 zeroCounter = 0; @@ -48152,7 +48252,6 @@ static drflac_bool32 drflac__decode_samples_with_residual__rice__scalar_zeroorde drflac_uint32 riceParamMask; drflac_uint32 i; DRFLAC_ASSERT(bs != NULL); - DRFLAC_ASSERT(count > 0); DRFLAC_ASSERT(pSamplesOut != NULL); (void)bitsPerSample; (void)order; @@ -48187,7 +48286,6 @@ static drflac_bool32 drflac__decode_samples_with_residual__rice__scalar(drflac_b const drflac_int32* pSamplesOutEnd; drflac_uint32 i; DRFLAC_ASSERT(bs != NULL); - DRFLAC_ASSERT(count > 0); DRFLAC_ASSERT(pSamplesOut != NULL); if (order == 0) { return drflac__decode_samples_with_residual__rice__scalar_zeroorder(bs, bitsPerSample, count, riceParam, order, shift, coefficients, pSamplesOut); @@ -48606,7 +48704,6 @@ static drflac_bool32 drflac__decode_samples_with_residual__rice__sse41_64(drflac static drflac_bool32 drflac__decode_samples_with_residual__rice__sse41(drflac_bs* bs, drflac_uint32 bitsPerSample, drflac_uint32 count, drflac_uint8 riceParam, drflac_uint32 order, drflac_int32 shift, const drflac_int32* coefficients, drflac_int32* pSamplesOut) { DRFLAC_ASSERT(bs != NULL); - DRFLAC_ASSERT(count > 0); DRFLAC_ASSERT(pSamplesOut != NULL); if (order > 0 && order <= 12) { if (bitsPerSample+shift > 32) { @@ -48957,7 +49054,6 @@ static drflac_bool32 drflac__decode_samples_with_residual__rice__neon_64(drflac_ static drflac_bool32 drflac__decode_samples_with_residual__rice__neon(drflac_bs* bs, drflac_uint32 bitsPerSample, drflac_uint32 count, drflac_uint8 riceParam, drflac_uint32 order, drflac_int32 shift, const drflac_int32* coefficients, drflac_int32* pSamplesOut) { DRFLAC_ASSERT(bs != NULL); - DRFLAC_ASSERT(count > 0); DRFLAC_ASSERT(pSamplesOut != NULL); if (order > 0 && order <= 12) { if (bitsPerSample+shift > 32) { @@ -48993,7 +49089,6 @@ static drflac_bool32 drflac__read_and_seek_residual__rice(drflac_bs* bs, drflac_ { drflac_uint32 i; DRFLAC_ASSERT(bs != NULL); - DRFLAC_ASSERT(count > 0); for (i = 0; i < count; ++i) { if (!drflac__seek_rice_parts(bs, riceParam)) { return DRFLAC_FALSE; @@ -49005,7 +49100,6 @@ static drflac_bool32 drflac__decode_samples_with_residual__unencoded(drflac_bs* { drflac_uint32 i; DRFLAC_ASSERT(bs != NULL); - DRFLAC_ASSERT(count > 0); DRFLAC_ASSERT(unencodedBitsPerSample <= 31); DRFLAC_ASSERT(pSamplesOut != NULL); for (i = 0; i < count; ++i) { @@ -49046,7 +49140,7 @@ static drflac_bool32 drflac__decode_samples_with_residual(drflac_bs* bs, drflac_ if (partitionOrder > 8) { return DRFLAC_FALSE; } - if ((blockSize / (1 << partitionOrder)) <= order) { + if ((blockSize / (1 << partitionOrder)) < order) { return DRFLAC_FALSE; } samplesInPartition = (blockSize / (1 << partitionOrder)) - order; @@ -54191,6 +54285,7 @@ DRFLAC_API drflac_bool32 drflac_seek_to_pcm_frame(drflac* pFlac, drflac_uint64 p return drflac__seek_to_first_frame(pFlac); } else { drflac_bool32 wasSuccessful = DRFLAC_FALSE; + drflac_uint64 originalPCMFrame = pFlac->currentPCMFrame; if (pcmFrameIndex > pFlac->totalPCMFrameCount) { pcmFrameIndex = pFlac->totalPCMFrameCount; } @@ -54231,7 +54326,13 @@ DRFLAC_API drflac_bool32 drflac_seek_to_pcm_frame(drflac* pFlac, drflac_uint64 p wasSuccessful = drflac__seek_to_pcm_frame__brute_force(pFlac, pcmFrameIndex); } } - pFlac->currentPCMFrame = pcmFrameIndex; + if (wasSuccessful) { + pFlac->currentPCMFrame = pcmFrameIndex; + } else { + if (drflac_seek_to_pcm_frame(pFlac, originalPCMFrame) == DRFLAC_FALSE) { + drflac_seek_to_pcm_frame(pFlac, 0); + } + } return wasSuccessful; } } diff --git a/extras/miniaudio_split/miniaudio.h b/extras/miniaudio_split/miniaudio.h index b1871fce..1e0b11de 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.32 - 2020-02-23 +miniaudio - v0.10.33 - 2021-04-04 David Reid - mackron@gmail.com @@ -20,7 +20,7 @@ extern "C" { #define MA_VERSION_MAJOR 0 #define MA_VERSION_MINOR 10 -#define MA_VERSION_REVISION 32 +#define MA_VERSION_REVISION 33 #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__) @@ -4330,7 +4330,7 @@ Offsets a pointer by the specified number of PCM frames. */ MA_API void* ma_offset_pcm_frames_ptr(void* p, ma_uint64 offsetInFrames, ma_format format, ma_uint32 channels); MA_API const void* ma_offset_pcm_frames_const_ptr(const void* p, ma_uint64 offsetInFrames, ma_format format, ma_uint32 channels); -static MA_INLINE float* ma_offset_pcm_frames_ptr_f32(float* p, ma_uint64 offsetInFrames, ma_uint32 channels) { return (float*)ma_offset_pcm_frames_const_ptr((void*)p, offsetInFrames, ma_format_f32, channels); } +static MA_INLINE float* ma_offset_pcm_frames_ptr_f32(float* p, ma_uint64 offsetInFrames, ma_uint32 channels) { return (float*)ma_offset_pcm_frames_ptr((void*)p, offsetInFrames, ma_format_f32, channels); } static MA_INLINE const float* ma_offset_pcm_frames_const_ptr_f32(const float* p, ma_uint64 offsetInFrames, ma_uint32 channels) { return (const float*)ma_offset_pcm_frames_const_ptr((const void*)p, offsetInFrames, ma_format_f32, channels); } diff --git a/miniaudio.h b/miniaudio.h index 4a0e97a2..60522da5 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.33 - TBD +miniaudio - v0.10.33 - 2021-04-04 David Reid - mackron@gmail.com @@ -64571,7 +64571,7 @@ The following miscellaneous changes have also been made. /* REVISION HISTORY ================ -v0.10.33 - TBD +v0.10.33 - 2021-04-04 - Core Audio: Fix a memory leak. - Core Audio: Fix a bug where the performance profile is not being used by playback devices. - JACK: Fix loading of 64-bit JACK on Windows. @@ -64579,6 +64579,7 @@ v0.10.33 - TBD - ma_calculate_buffer_size_in_milliseconds_from_frames() - ma_calculate_buffer_size_in_frames_from_milliseconds() - Fix compilation errors relating to c89atomic. + - Update FLAC decoder. v0.10.32 - 2021-02-23 - WASAPI: Fix a deadlock in exclusive mode.