AAX SDK 2.6.1
Avid Audio Extensions Development Kit
Loading...
Searching...
No Matches
AAX_Denormal.h
Go to the documentation of this file.
1/*================================================================================================*/
2/*
3 * Copyright 2014-2016, 2019, 2021, 2023 Avid Technology, Inc.
4 * All rights reserved.
5 *
6 * CONFIDENTIAL: this document contains confidential information of Avid. Do
7 * not disclose to any third party. Use of the information contained in this
8 * document is subject to an Avid SDK license.
9 */
10
17/*================================================================================================*/
18#pragma once
19
20#ifndef AAX_DENORMAL_H
21#define AAX_DENORMAL_H
22
23
24// AAX Includes
25#include "AAX.h"
27
28
29#if ! defined( _TMS320C6X )
30#include <limits>
31#include <math.h>
32#endif // ! defined( _TMS320C6X )
33
34
35
53#if defined( _TMS320C6X )
54
55// TODO: Currently noop on TI
56#define AAX_SCOPE_COMPUTE_DENORMALS() do {} while(0)
57#define AAX_SCOPE_DENORMALS_AS_ZERO() do {} while(0)
58
59#elif ((defined _MSC_VER) || defined(WINDOWS_VERSION))
60// Visual Studio
61
62// Note: In Pro Tools 11 and higher for Windows, DAZ is turned on for all plug-in processing threads
63
64// FIXME: These macros are currently noop on Windows because of compiler problems when intrin.h is included. Investigate using _controlfp(_DN_FLUSH, _MCW_DN) instead
65#define AAX_SCOPE_COMPUTE_DENORMALS() do {} while(0)
66#define AAX_SCOPE_DENORMALS_AS_ZERO() do {} while(0)
67//#define AAX_SCOPE_COMPUTE_DENORMALS() AAX_StDenormalAsZeroFlagsOff computeDenormalFlagsScope ## __LINE__ ; do {} while (0)
68//#define AAX_SCOPE_DENORMALS_AS_ZERO() AAX_StDenormalAsZeroFlagsOn denormalAsZeroFlagsScope ## __LINE__ ; do {} while (0)
69//
70//#include <Windows.h>
71//#include <mmintrin.h>
72//
78//const unsigned gMXCSRFlags_DAZFZ = 0x00008040;
79//
81//struct AAX_StDenormalAsZeroFlagsOn
82//{
83//public:
84// AAX_StDenormalAsZeroFlagsOn()
85// : mSSESupported(IsProcessorFeaturePresent(PF_XMMI_INSTRUCTIONS_AVAILABLE))
86// {
87// if (mSSESupported) { set_flags(); }
88// }
89//
90// ~AAX_StDenormalAsZeroFlagsOn()
91// {
92// if (mSSESupported) { reset_flags(); }
93// }
94//
95//private:
96// void set_flags()
97// {
98// mPrevFlags = _mm_getcsr();
99// unsigned newFlags = mPrevFlags | gMXCSRFlags_DAZFZ;
100// _mm_setcsr(newFlags);
101// }
102//
103// void reset_flags()
104// {
105// _mm_setcsr(mPrevFlags);
106// }
107//
108// unsigned mPrevFlags;
109// const bool mSSESupported;
110//};
111//
113//struct AAX_StDenormalAsZeroFlagsOff
114//{
115//public:
116// AAX_StDenormalAsZeroFlagsOff()
117// : mSSESupported(IsProcessorFeaturePresent(PF_XMMI_INSTRUCTIONS_AVAILABLE))
118// {
119// if (mSSESupported) { set_flags(); }
120// }
121//
122// ~AAX_StDenormalAsZeroFlagsOff()
123// {
124// if (mSSESupported) { reset_flags(); }
125// }
126//
127//private:
128// void set_flags()
129// {
130// mPrevFlags = _mm_getcsr();
131// unsigned newFlags = mPrevFlags & (~gMXCSRFlags_DAZFZ);
132// _mm_setcsr(newFlags);
133// }
134//
135// void reset_flags()
136// {
137// _mm_setcsr(mPrevFlags);
138// }
139//
140// unsigned mPrevFlags;
141// const bool mSSESupported;
142//};
143
144
145#elif defined(__linux__)
146// Linux
147
148// TODO: Currently noop on Linux
149#define AAX_SCOPE_COMPUTE_DENORMALS() do {} while(0)
150#define AAX_SCOPE_DENORMALS_AS_ZERO() do {} while(0)
151
152#elif (defined (__GNUC__) || defined(MAC_VERSION))
153// GCC / macOS
154
155// Note: In Pro Tools 11 through Pro Tools 12.6 on macOS, DAZ is turned off for all plug-in processing threads
156
157#define AAX_SCOPE_COMPUTE_DENORMALS() AAX_StDenormalAsZeroFlagsOff computeDenormalFlagsScope ## __LINE__ ; do {} while (0)
158#define AAX_SCOPE_DENORMALS_AS_ZERO() AAX_StDenormalAsZeroFlagsOn denormalAsZeroFlagsScope ## __LINE__ ; do {} while (0)
159
160#include <fenv.h>
161struct AAX_StDenormalAsZeroFlagsOn
162{
163public:
164 AAX_StDenormalAsZeroFlagsOn() { set_flags(); }
165 ~AAX_StDenormalAsZeroFlagsOn() { reset_flags(); }
166
167private:
168#if !defined(__arm64__)
169 void set_flags() { fegetenv(&mPrevFlags); fesetenv(FE_DFL_DISABLE_SSE_DENORMS_ENV); }
170#else
171 void set_flags() { fegetenv(&mPrevFlags); fesetenv(FE_DFL_DISABLE_DENORMS_ENV); }
172#endif
173 void reset_flags() { fesetenv(&mPrevFlags); }
174 fenv_t mPrevFlags;
175};
176struct AAX_StDenormalAsZeroFlagsOff
177{
178public:
179 AAX_StDenormalAsZeroFlagsOff() { set_flags(); }
180 ~AAX_StDenormalAsZeroFlagsOff() { reset_flags(); }
181
182private:
183 void set_flags() { fegetenv(&mPrevFlags); fesetenv(FE_DFL_ENV); } // assuming that FE_DFL_ENV are the flags that we want here
184 void reset_flags() { fesetenv(&mPrevFlags); }
185 fenv_t mPrevFlags;
186};
187
188
189
190#else
191
192#error AAX_SCOPE_COMPUTE_DENORMALS is not defined for this compiler
193#error AAX_SCOPE_DENORMALS_AS_ZERO is not defined for this compiler
194
195// Just for Doxygen
196#define AAX_SCOPE_COMPUTE_DENORMALS() do {} while(0)
197#define AAX_SCOPE_DENORMALS_AS_ZERO() do {} while(0)
198
199#endif // End compiler selection for AAX_SCOPE_COMPUTE_DENORMALS / AAX_SCOPE_DENORMALS_AS_ZERO definition
200
201
202
203
204namespace AAX
205{
206 const double cDenormalAvoidanceOffset=3.0e-34;
207 const float cFloatDenormalAvoidanceOffset=3.0e-20f; //This number is emprically derived with minimal trial and error.
208
209#if ! defined( _TMS320C6X )
210 static const float cMinimumNormalFloat = std::numeric_limits<float>::min();
211#endif
212
222 inline void DeDenormal(double &iValue)
223 {
224#if defined(WINDOWS_VERSION) || defined(MAC_VERSION) || defined(LINUX_VERSION)
225 if(iValue < cDenormalAvoidanceOffset && iValue > -cDenormalAvoidanceOffset) iValue=0.0;
226#endif
227 }
228
231 inline void DeDenormal(float &iValue)
232 {
233#if defined(WINDOWS_VERSION) || defined(MAC_VERSION) || defined(LINUX_VERSION)
234 if(iValue < cFloatDenormalAvoidanceOffset && iValue > -cFloatDenormalAvoidanceOffset) iValue=0.0f;
235#endif
236 }
237
238#if AAX_CPP11_SUPPORT
241 inline float DeDenormal(float &&iValue)
242 {
243#if defined(WINDOWS_VERSION) || defined(MAC_VERSION) || defined(LINUX_VERSION)
244 return (iValue < cFloatDenormalAvoidanceOffset && iValue > -cFloatDenormalAvoidanceOffset) ? 0.f : iValue;
245#endif
246 }
247#endif // AAX_CPP11_SUPPORT
248
253 inline void DeDenormalFine(float &iValue)
254 {
255#if ! defined( _TMS320C6X )
256 if(iValue < cMinimumNormalFloat && iValue > -cMinimumNormalFloat) iValue=0.0f;
257#endif
258 }
259
270 inline void FilterDenormals(float* inSamples, int32_t inLength)
271 {
272 //TODO: Implement optimized versions for TI and SSE
273#if ! defined( _TMS320C6X ) // Not yet implemented for TI
274 for( int32_t i = 0; i < inLength; ++i )
275 {
276 float curFloat = *inSamples;
277 if( fabsf(curFloat) < cMinimumNormalFloat )
278 curFloat = 0.0f;
279 *(inSamples++) = curFloat;
280 }
281#endif
282 }
283
284} // namespace AAX
285
286#endif // AAX_QUANTIZE_H
Various utility definitions for AAX.
Definition: AAX_EnvironmentUtilities.h:59
const double cDenormalAvoidanceOffset
Definition: AAX_Denormal.h:206
void FilterDenormals(float *inSamples, int32_t inLength)
Round all denormal/subnormal samples in a buffer to zero.
Definition: AAX_Denormal.h:270
float fabsf(float iVal)
Definition: AAX_MiscUtils.h:182
void DeDenormal(double &iValue)
Clamps very small floating point values to zero.
Definition: AAX_Denormal.h:222
void DeDenormalFine(float &iValue)
Definition: AAX_Denormal.h:253
const float cFloatDenormalAvoidanceOffset
Definition: AAX_Denormal.h:207