AAX SDK  2.4.1
Avid Audio Extensions Development Kit
AAX_Denormal.h
Go to the documentation of this file.
1 /*================================================================================================*/
2 /*
3  * Copyright 2014-2016, 2019, 2021 by Avid Technology, Inc.
4  * All rights reserved.
5  *
6  * CONFIDENTIAL: This document contains confidential information. Do not
7  * read or examine this document unless you are an Avid Technology employee
8  * or have signed a non-disclosure agreement with Avid Technology which protects
9  * the confidentiality of this document. DO NOT DISCLOSE ANY INFORMATION
10  * CONTAINED IN THIS DOCUMENT TO ANY THIRD-PARTY WITHOUT THE PRIOR WRITTEN CONSENT
11  * OF Avid Technology, INC.
12  */
13 
20 /*================================================================================================*/
21 #pragma once
22 
23 #ifndef AAX_DENORMAL_H
24 #define AAX_DENORMAL_H
25 
26 
27 // AAX Includes
28 #include "AAX.h"
30 
31 
32 #if ! defined( _TMS320C6X )
33 #include <limits>
34 #include <math.h>
35 #endif // ! defined( _TMS320C6X )
36 
37 
38 
56 #if defined( _TMS320C6X )
57 
58 // TODO: Currently noop on TI
59 #define AAX_SCOPE_COMPUTE_DENORMALS() do {} while(0)
60 #define AAX_SCOPE_DENORMALS_AS_ZERO() do {} while(0)
61 
62 #elif ((defined _MSC_VER) || defined(WINDOWS_VERSION))
63 // Visual Studio
64 
65 // Note: In Pro Tools 11 and higher for Windows, DAZ is turned on for all plug-in processing threads
66 
67 // 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
68 #define AAX_SCOPE_COMPUTE_DENORMALS() do {} while(0)
69 #define AAX_SCOPE_DENORMALS_AS_ZERO() do {} while(0)
70 //#define AAX_SCOPE_COMPUTE_DENORMALS() AAX_StDenormalAsZeroFlagsOff computeDenormalFlagsScope ## __LINE__ ; do {} while (0)
71 //#define AAX_SCOPE_DENORMALS_AS_ZERO() AAX_StDenormalAsZeroFlagsOn denormalAsZeroFlagsScope ## __LINE__ ; do {} while (0)
72 //
73 //#include <Windows.h>
74 //#include <mmintrin.h>
75 //
81 //const unsigned gMXCSRFlags_DAZFZ = 0x00008040;
82 //
84 //struct AAX_StDenormalAsZeroFlagsOn
85 //{
86 //public:
87 // AAX_StDenormalAsZeroFlagsOn()
88 // : mSSESupported(IsProcessorFeaturePresent(PF_XMMI_INSTRUCTIONS_AVAILABLE))
89 // {
90 // if (mSSESupported) { set_flags(); }
91 // }
92 //
93 // ~AAX_StDenormalAsZeroFlagsOn()
94 // {
95 // if (mSSESupported) { reset_flags(); }
96 // }
97 //
98 //private:
99 // void set_flags()
100 // {
101 // mPrevFlags = _mm_getcsr();
102 // unsigned newFlags = mPrevFlags | gMXCSRFlags_DAZFZ;
103 // _mm_setcsr(newFlags);
104 // }
105 //
106 // void reset_flags()
107 // {
108 // _mm_setcsr(mPrevFlags);
109 // }
110 //
111 // unsigned mPrevFlags;
112 // const bool mSSESupported;
113 //};
114 //
116 //struct AAX_StDenormalAsZeroFlagsOff
117 //{
118 //public:
119 // AAX_StDenormalAsZeroFlagsOff()
120 // : mSSESupported(IsProcessorFeaturePresent(PF_XMMI_INSTRUCTIONS_AVAILABLE))
121 // {
122 // if (mSSESupported) { set_flags(); }
123 // }
124 //
125 // ~AAX_StDenormalAsZeroFlagsOff()
126 // {
127 // if (mSSESupported) { reset_flags(); }
128 // }
129 //
130 //private:
131 // void set_flags()
132 // {
133 // mPrevFlags = _mm_getcsr();
134 // unsigned newFlags = mPrevFlags & (~gMXCSRFlags_DAZFZ);
135 // _mm_setcsr(newFlags);
136 // }
137 //
138 // void reset_flags()
139 // {
140 // _mm_setcsr(mPrevFlags);
141 // }
142 //
143 // unsigned mPrevFlags;
144 // const bool mSSESupported;
145 //};
146 
147 
148 #elif defined(LINUX_VERSION)
149 // Linux
150 
151 // TODO: Currently noop on Linux
152 #define AAX_SCOPE_COMPUTE_DENORMALS() do {} while(0)
153 #define AAX_SCOPE_DENORMALS_AS_ZERO() do {} while(0)
154 
155 #elif (defined (__GNUC__) || defined(MAC_VERSION))
156 // GCC / OS X
157 
158 // Note: In Pro Tools 11 through Pro Tools 12.6 on OS X, DAZ is turned off for all plug-in processing threads
159 
160 #define AAX_SCOPE_COMPUTE_DENORMALS() AAX_StDenormalAsZeroFlagsOff computeDenormalFlagsScope ## __LINE__ ; do {} while (0)
161 #define AAX_SCOPE_DENORMALS_AS_ZERO() AAX_StDenormalAsZeroFlagsOn denormalAsZeroFlagsScope ## __LINE__ ; do {} while (0)
162 
163 #include <fenv.h>
164 struct AAX_StDenormalAsZeroFlagsOn
165 {
166 public:
167  AAX_StDenormalAsZeroFlagsOn() { set_flags(); }
168  ~AAX_StDenormalAsZeroFlagsOn() { reset_flags(); }
169 
170 private:
171 #if !defined(__arm64__)
172  void set_flags() { fegetenv(&mPrevFlags); fesetenv(FE_DFL_DISABLE_SSE_DENORMS_ENV); }
173 #else
174  void set_flags() { fegetenv(&mPrevFlags); fesetenv(FE_DFL_DISABLE_DENORMS_ENV); }
175 #endif
176  void reset_flags() { fesetenv(&mPrevFlags); }
177  fenv_t mPrevFlags;
178 };
179 struct AAX_StDenormalAsZeroFlagsOff
180 {
181 public:
182  AAX_StDenormalAsZeroFlagsOff() { set_flags(); }
183  ~AAX_StDenormalAsZeroFlagsOff() { reset_flags(); }
184 
185 private:
186  void set_flags() { fegetenv(&mPrevFlags); fesetenv(FE_DFL_ENV); } // assuming that FE_DFL_ENV are the flags that we want here
187  void reset_flags() { fesetenv(&mPrevFlags); }
188  fenv_t mPrevFlags;
189 };
190 
191 
192 
193 #else
194 
195 #error AAX_SCOPE_COMPUTE_DENORMALS is not defined for this compiler
196 #error AAX_SCOPE_DENORMALS_AS_ZERO is not defined for this compiler
197 
198 // Just for Doxygen
199 #define AAX_SCOPE_COMPUTE_DENORMALS() do {} while(0)
200 #define AAX_SCOPE_DENORMALS_AS_ZERO() do {} while(0)
201 
202 #endif // End compiler selection for AAX_SCOPE_COMPUTE_DENORMALS / AAX_SCOPE_DENORMALS_AS_ZERO definition
203 
204 
205 
206 
207 namespace AAX
208 {
209  const double cDenormalAvoidanceOffset=3.0e-34;
210  const float cFloatDenormalAvoidanceOffset=3.0e-20f; //This number is emprically derived with minimal trial and error.
211 
212 #if ! defined( _TMS320C6X )
213  static const float cMinimumNormalFloat = std::numeric_limits<float>::min();
214 #endif
215 
225  inline void DeDenormal(double &iValue)
226  {
227 #if defined(WINDOWS_VERSION) || defined(MAC_VERSION) || defined(LINUX_VERSION)
228  if(iValue < cDenormalAvoidanceOffset && iValue > -cDenormalAvoidanceOffset) iValue=0.0;
229 #endif
230  }
231 
234  inline void DeDenormal(float &iValue)
235  {
236 #if defined(WINDOWS_VERSION) || defined(MAC_VERSION) || defined(LINUX_VERSION)
237  if(iValue < cFloatDenormalAvoidanceOffset && iValue > -cFloatDenormalAvoidanceOffset) iValue=0.0f;
238 #endif
239  }
240 
241 #if AAX_CPP11_SUPPORT
244  inline float DeDenormal(float &&iValue)
245  {
246 #if defined(WINDOWS_VERSION) || defined(MAC_VERSION) || defined(LINUX_VERSION)
247  return (iValue < cFloatDenormalAvoidanceOffset && iValue > -cFloatDenormalAvoidanceOffset) ? 0.f : iValue;
248 #endif
249  }
250 #endif // AAX_CPP11_SUPPORT
251 
256  inline void DeDenormalFine(float &iValue)
257  {
258 #if ! defined( _TMS320C6X )
259  if(iValue < cMinimumNormalFloat && iValue > -cMinimumNormalFloat) iValue=0.0f;
260 #endif
261  }
262 
273  inline void FilterDenormals(float* inSamples, int32_t inLength)
274  {
275  //TODO: Implement optimized versions for TI and SSE
276 #if ! defined( _TMS320C6X ) // Not yet implemented for TI
277  for( int32_t i = 0; i < inLength; ++i )
278  {
279  float curFloat = *inSamples;
280  if( fabsf(curFloat) < cMinimumNormalFloat )
281  curFloat = 0.0f;
282  *(inSamples++) = curFloat;
283  }
284 #endif
285  }
286 
287 } // namespace AAX
288 
289 #endif // AAX_QUANTIZE_H
Various utility definitions for AAX.
Definition: AAX_Exception.h:42
const double cDenormalAvoidanceOffset
Definition: AAX_Denormal.h:209
void FilterDenormals(float *inSamples, int32_t inLength)
Round all denormal/subnormal samples in a buffer to zero.
Definition: AAX_Denormal.h:273
float fabsf(float iVal)
Definition: AAX_MiscUtils.h:185
void DeDenormal(double &iValue)
Clamps very small floating point values to zero.
Definition: AAX_Denormal.h:225
void DeDenormalFine(float &iValue)
Definition: AAX_Denormal.h:256
const float cFloatDenormalAvoidanceOffset
Definition: AAX_Denormal.h:210