WebAudioUtils.h (5654B)
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim:set ts=2 sw=2 sts=2 et cindent: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #ifndef WebAudioUtils_h_ 8 #define WebAudioUtils_h_ 9 10 #include <cmath> 11 #include <limits> 12 #include <type_traits> 13 14 #include "MediaSegment.h" 15 #include "fdlibm.h" 16 #include "mozilla/Logging.h" 17 18 // Forward declaration 19 typedef struct SpeexResamplerState_ SpeexResamplerState; 20 21 namespace mozilla { 22 23 extern LazyLogModule gWebAudioAPILog; 24 #define WEB_AUDIO_API_LOG(...) \ 25 MOZ_LOG_FMT(gWebAudioAPILog, LogLevel::Debug, __VA_ARGS__) 26 #define WEB_AUDIO_API_LOG_TEST(...) \ 27 MOZ_LOG_TEST(gWebAudioAPILog, LogLevel::Debug) 28 29 namespace dom::WebAudioUtils { 30 31 // 32 is the minimum required by the spec for createBuffer() and 32 // createScriptProcessor() and matches what is used by Blink. The limit 33 // protects against large memory allocations. 34 const size_t MaxChannelCount = 32; 35 // AudioContext::CreateBuffer() "must support sample-rates in at least the 36 // range 22050 to 96000." 37 const uint32_t MinSampleRate = 8000; 38 const uint32_t MaxSampleRate = 768000; 39 40 inline bool FuzzyEqual(float v1, float v2) { return fabsf(v1 - v2) < 1e-7f; } 41 inline bool FuzzyEqual(double v1, double v2) { return fabs(v1 - v2) < 1e-7; } 42 43 /** 44 * Converts a linear value to decibels. Returns aMinDecibels if the linear 45 * value is 0. 46 */ 47 inline float ConvertLinearToDecibels(float aLinearValue, float aMinDecibels) { 48 MOZ_ASSERT(aLinearValue >= 0); 49 return aLinearValue > 0.0f ? 20.0f * fdlibm_log10f(aLinearValue) 50 : aMinDecibels; 51 } 52 53 /** 54 * Converts a decibel value to a linear value. 55 */ 56 inline float ConvertDecibelsToLinear(float aDecibels) { 57 return fdlibm_powf(10.0f, 0.05f * aDecibels); 58 } 59 60 inline void FixNaN(double& aDouble) { 61 if (std::isnan(aDouble) || std::isinf(aDouble)) { 62 aDouble = 0.0; 63 } 64 } 65 66 inline double DiscreteTimeConstantForSampleRate(double timeConstant, 67 double sampleRate) { 68 return 1.0 - fdlibm_exp(-1.0 / (sampleRate * timeConstant)); 69 } 70 71 inline bool IsTimeValid(double aTime) { 72 return aTime >= 0 && aTime <= (MEDIA_TIME_MAX >> TRACK_RATE_MAX_BITS); 73 } 74 75 /** 76 * Converts a floating point value to an integral type in a safe and 77 * platform agnostic way. The following program demonstrates the kinds 78 * of ways things can go wrong depending on the CPU architecture you're 79 * compiling for: 80 * 81 * #include <stdio.h> 82 * volatile float r; 83 * int main() 84 * { 85 * unsigned int q; 86 * r = 1e100; 87 * q = r; 88 * printf("%f %d\n", r, q); 89 * r = -1e100; 90 * q = r; 91 * printf("%f %d\n", r, q); 92 * r = 1e15; 93 * q = r; 94 * printf("%f %x\n", r, q); 95 * r = 0/0.; 96 * q = r; 97 * printf("%f %d\n", r, q); 98 * } 99 * 100 * This program, when compiled for unsigned int, generates the following 101 * results depending on the architecture: 102 * 103 * x86 and x86-64 104 * --- 105 * inf 0 106 * -inf 0 107 * 999999995904.000000 -727384064 d4a50000 108 * nan 0 109 * 110 * ARM 111 * --- 112 * inf -1 113 * -inf 0 114 * 999999995904.000000 -1 115 * nan 0 116 * 117 * When compiled for int, this program generates the following results: 118 * 119 * x86 and x86-64 120 * --- 121 * inf -2147483648 122 * -inf -2147483648 123 * 999999995904.000000 -2147483648 124 * nan -2147483648 125 * 126 * ARM 127 * --- 128 * inf 2147483647 129 * -inf -2147483648 130 * 999999995904.000000 2147483647 131 * nan 0 132 * 133 * Note that the caller is responsible to make sure that the value 134 * passed to this function is not a NaN. This function will abort if 135 * it sees a NaN. 136 */ 137 template <typename IntType, typename FloatType> 138 IntType TruncateFloatToInt(FloatType f) { 139 using std::numeric_limits; 140 static_assert(std::is_integral_v<IntType> == true, 141 "IntType must be an integral type"); 142 static_assert(std::is_floating_point_v<FloatType> == true, 143 "FloatType must be a floating point type"); 144 145 if (std::isnan(f)) { 146 // It is the responsibility of the caller to deal with NaN values. 147 // If we ever get to this point, we have a serious bug to fix. 148 MOZ_CRASH("We should never see a NaN here"); 149 } 150 151 // If the floating point value is outside of the range of maximum 152 // integral value for this type, just clamp to the maximum value. 153 // The equality case must also return max() due to loss of precision when 154 // converting max() to float. 155 if (f >= FloatType(numeric_limits<IntType>::max())) { 156 return numeric_limits<IntType>::max(); 157 } 158 159 if (f <= FloatType(numeric_limits<IntType>::min())) { 160 // If the floating point value is outside of the range of minimum 161 // integral value for this type, just clamp to the minimum value. 162 return numeric_limits<IntType>::min(); 163 } 164 165 // Otherwise, this conversion must be well defined. 166 return IntType(f); 167 } 168 169 void Shutdown(); 170 171 int SpeexResamplerProcess(SpeexResamplerState* aResampler, uint32_t aChannel, 172 const float* aIn, uint32_t* aInLen, float* aOut, 173 uint32_t* aOutLen); 174 175 int SpeexResamplerProcess(SpeexResamplerState* aResampler, uint32_t aChannel, 176 const int16_t* aIn, uint32_t* aInLen, float* aOut, 177 uint32_t* aOutLen); 178 179 int SpeexResamplerProcess(SpeexResamplerState* aResampler, uint32_t aChannel, 180 const int16_t* aIn, uint32_t* aInLen, int16_t* aOut, 181 uint32_t* aOutLen); 182 183 void LogToDeveloperConsole(uint64_t aWindowID, const char* aKey); 184 185 } // namespace dom::WebAudioUtils 186 } // namespace mozilla 187 188 #endif