Commit 643c9c08 authored by David Reid's avatar David Reid

Add support for disabling denormals on the audio thread.

This is configurable on a per-device basis. Denormals will be disabled
by default.
parent b961cdf9
...@@ -3370,6 +3370,7 @@ struct ma_device_config ...@@ -3370,6 +3370,7 @@ struct ma_device_config
ma_performance_profile performanceProfile; ma_performance_profile performanceProfile;
ma_bool8 noPreSilencedOutputBuffer; /* When set to true, the contents of the output buffer passed into the data callback will be left undefined rather than initialized to silence. */ ma_bool8 noPreSilencedOutputBuffer; /* When set to true, the contents of the output buffer passed into the data callback will be left undefined rather than initialized to silence. */
ma_bool8 noClip; /* When set to true, the contents of the output buffer passed into the data callback will be clipped after returning. Only applies when the playback sample format is f32. */ ma_bool8 noClip; /* When set to true, the contents of the output buffer passed into the data callback will be clipped after returning. Only applies when the playback sample format is f32. */
ma_bool8 noDisableDenormals; /* Do not disable denormals when firing the data callback. */
ma_device_data_proc dataCallback; ma_device_data_proc dataCallback;
ma_stop_proc stopCallback; ma_stop_proc stopCallback;
void* pUserData; void* pUserData;
...@@ -4033,6 +4034,7 @@ struct ma_device ...@@ -4033,6 +4034,7 @@ struct ma_device
ma_bool8 isOwnerOfContext; /* When set to true, uninitializing the device will also uninitialize the context. Set to true when NULL is passed into ma_device_init(). */ ma_bool8 isOwnerOfContext; /* When set to true, uninitializing the device will also uninitialize the context. Set to true when NULL is passed into ma_device_init(). */
ma_bool8 noPreSilencedOutputBuffer; ma_bool8 noPreSilencedOutputBuffer;
ma_bool8 noClip; ma_bool8 noClip;
ma_bool8 noDisableDenormals;
MA_ATOMIC float masterVolumeFactor; /* Linear 0..1. Can be read and written simultaneously by different threads. Must be used atomically. */ MA_ATOMIC float masterVolumeFactor; /* Linear 0..1. Can be read and written simultaneously by different threads. Must be used atomically. */
ma_duplex_rb duplexRB; /* Intermediary buffer for duplex device on asynchronous backends. */ ma_duplex_rb duplexRB; /* Intermediary buffer for duplex device on asynchronous backends. */
struct struct
...@@ -4888,6 +4890,9 @@ then be set directly on the structure. Below are the members of the `ma_device_c ...@@ -4888,6 +4890,9 @@ then be set directly on the structure. Below are the members of the `ma_device_c
contents of the output buffer are left alone after returning and it will be left up to the backend itself to decide whether or not the clip. This only contents of the output buffer are left alone after returning and it will be left up to the backend itself to decide whether or not the clip. This only
applies when the playback sample format is f32. applies when the playback sample format is f32.
noDisableDenormals
By default, miniaudio will disable denormals when the data callback is called. Setting this to true will prevent the disabling of denormals.
dataCallback dataCallback
The callback to fire whenever data is ready to be delivered to or from the device. The callback to fire whenever data is ready to be delivered to or from the device.
...@@ -6915,6 +6920,32 @@ static MA_INLINE void ma_yield() ...@@ -6915,6 +6920,32 @@ static MA_INLINE void ma_yield()
} }
static MA_INLINE unsigned int ma_disable_denormals()
{
unsigned int prevState;
#if defined(MA_X86) || defined(MA_X64)
prevState = _mm_getcsr();
_mm_setcsr(prevState | _MM_DENORMALS_ZERO_MASK | _MM_FLUSH_ZERO_MASK);
#else
/* Unknown or unsupported architecture. No-op. */
prevState = 0;
#endif
return prevState;
}
static MA_INLINE void ma_restore_denormals(unsigned int prevState)
{
#if defined(MA_X86) || defined(MA_X64)
_mm_setcsr(prevState);
#else
/* Unknown or unsupported architecture. No-op. */
(void)prevState;
#endif
}
#ifndef MA_COINIT_VALUE #ifndef MA_COINIT_VALUE
#define MA_COINIT_VALUE 0 /* 0 = COINIT_MULTITHREADED */ #define MA_COINIT_VALUE 0 /* 0 = COINIT_MULTITHREADED */
...@@ -11921,6 +11952,29 @@ static ma_uint32 ma_get_closest_standard_sample_rate(ma_uint32 sampleRateIn) ...@@ -11921,6 +11952,29 @@ static ma_uint32 ma_get_closest_standard_sample_rate(ma_uint32 sampleRateIn)
#endif #endif
static MA_INLINE unsigned int ma_device_disable_denormals(ma_device* pDevice)
{
MA_ASSERT(pDevice != NULL);
if (pDevice->noDisableDenormals) {
return ma_disable_denormals();
} else {
return 0;
}
}
static MA_INLINE void ma_device_restore_denormals(ma_device* pDevice, unsigned int prevState)
{
MA_ASSERT(pDevice != NULL);
if (pDevice->noDisableDenormals) {
ma_restore_denormals(prevState);
} else {
/* Do nothing. */
(void)prevState;
}
}
static void ma_device__on_data(ma_device* pDevice, void* pFramesOut, const void* pFramesIn, ma_uint32 frameCount) static void ma_device__on_data(ma_device* pDevice, void* pFramesOut, const void* pFramesIn, ma_uint32 frameCount)
{ {
float masterVolumeFactor; float masterVolumeFactor;
...@@ -11928,6 +11982,8 @@ static void ma_device__on_data(ma_device* pDevice, void* pFramesOut, const void* ...@@ -11928,6 +11982,8 @@ static void ma_device__on_data(ma_device* pDevice, void* pFramesOut, const void*
ma_device_get_master_volume(pDevice, &masterVolumeFactor); /* Use ma_device_get_master_volume() to ensure the volume is loaded atomically. */ ma_device_get_master_volume(pDevice, &masterVolumeFactor); /* Use ma_device_get_master_volume() to ensure the volume is loaded atomically. */
if (pDevice->onData) { if (pDevice->onData) {
unsigned int prevDenormalState = ma_device_disable_denormals(pDevice);
{
if (!pDevice->noPreSilencedOutputBuffer && pFramesOut != NULL) { if (!pDevice->noPreSilencedOutputBuffer && pFramesOut != NULL) {
ma_silence_pcm_frames(pFramesOut, frameCount, pDevice->playback.format, pDevice->playback.channels); ma_silence_pcm_frames(pFramesOut, frameCount, pDevice->playback.format, pDevice->playback.channels);
} }
...@@ -11967,6 +12023,8 @@ static void ma_device__on_data(ma_device* pDevice, void* pFramesOut, const void* ...@@ -11967,6 +12023,8 @@ static void ma_device__on_data(ma_device* pDevice, void* pFramesOut, const void*
} }
} }
} }
ma_device_restore_denormals(pDevice, prevDenormalState);
}
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment