1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/content/media/webaudio/WebAudioUtils.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,231 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* vim:set ts=2 sw=2 sts=2 et cindent: */ 1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#ifndef WebAudioUtils_h_ 1.11 +#define WebAudioUtils_h_ 1.12 + 1.13 +#include <cmath> 1.14 +#include <limits> 1.15 +#include "mozilla/TypeTraits.h" 1.16 +#include "mozilla/FloatingPoint.h" 1.17 +#include "MediaSegment.h" 1.18 + 1.19 +// Forward declaration 1.20 +typedef struct SpeexResamplerState_ SpeexResamplerState; 1.21 + 1.22 +namespace mozilla { 1.23 + 1.24 +class AudioNodeStream; 1.25 + 1.26 +namespace dom { 1.27 + 1.28 +class AudioParamTimeline; 1.29 + 1.30 +namespace WebAudioUtils { 1.31 + // 32 is the minimum required by the spec for createBuffer() and 1.32 + // createScriptProcessor() and matches what is used by Blink. The limit 1.33 + // protects against large memory allocations. 1.34 + const uint32_t MaxChannelCount = 32; 1.35 + // AudioContext::CreateBuffer() "must support sample-rates in at least the 1.36 + // range 22050 to 96000." 1.37 + const uint32_t MinSampleRate = 8000; 1.38 + const uint32_t MaxSampleRate = 192000; 1.39 + 1.40 + inline bool FuzzyEqual(float v1, float v2) 1.41 + { 1.42 + using namespace std; 1.43 + return fabsf(v1 - v2) < 1e-7f; 1.44 + } 1.45 + inline bool FuzzyEqual(double v1, double v2) 1.46 + { 1.47 + using namespace std; 1.48 + return fabs(v1 - v2) < 1e-7; 1.49 + } 1.50 + 1.51 + /** 1.52 + * Computes an exponential smoothing rate for a time based variable 1.53 + * over aDuration seconds. 1.54 + */ 1.55 + inline double ComputeSmoothingRate(double aDuration, double aSampleRate) 1.56 + { 1.57 + return 1.0 - std::exp(-1.0 / (aDuration * aSampleRate)); 1.58 + } 1.59 + 1.60 + /** 1.61 + * Converts AudioParamTimeline floating point time values to tick values 1.62 + * with respect to a source and a destination AudioNodeStream. 1.63 + * 1.64 + * This needs to be called for each AudioParamTimeline that gets sent to an 1.65 + * AudioNodeEngine on the engine side where the AudioParamTimeline is 1.66 + * received. This means that such engines need to be aware of their source 1.67 + * and destination streams as well. 1.68 + */ 1.69 + void ConvertAudioParamToTicks(AudioParamTimeline& aParam, 1.70 + AudioNodeStream* aSource, 1.71 + AudioNodeStream* aDest); 1.72 + 1.73 + /** 1.74 + * Converts a linear value to decibels. Returns aMinDecibels if the linear 1.75 + * value is 0. 1.76 + */ 1.77 + inline float ConvertLinearToDecibels(float aLinearValue, float aMinDecibels) 1.78 + { 1.79 + return aLinearValue ? 20.0f * std::log10(aLinearValue) : aMinDecibels; 1.80 + } 1.81 + 1.82 + /** 1.83 + * Converts a decibel value to a linear value. 1.84 + */ 1.85 + inline float ConvertDecibelsToLinear(float aDecibels) 1.86 + { 1.87 + return std::pow(10.0f, 0.05f * aDecibels); 1.88 + } 1.89 + 1.90 + /** 1.91 + * Converts a decibel to a linear value. 1.92 + */ 1.93 + inline float ConvertDecibelToLinear(float aDecibel) 1.94 + { 1.95 + return std::pow(10.0f, 0.05f * aDecibel); 1.96 + } 1.97 + 1.98 + inline void FixNaN(double& aDouble) 1.99 + { 1.100 + if (IsNaN(aDouble) || IsInfinite(aDouble)) { 1.101 + aDouble = 0.0; 1.102 + } 1.103 + } 1.104 + 1.105 + inline double DiscreteTimeConstantForSampleRate(double timeConstant, double sampleRate) 1.106 + { 1.107 + return 1.0 - std::exp(-1.0 / (sampleRate * timeConstant)); 1.108 + } 1.109 + 1.110 + inline bool IsTimeValid(double aTime) 1.111 + { 1.112 + return aTime >= 0 && aTime <= (MEDIA_TIME_MAX >> MEDIA_TIME_FRAC_BITS); 1.113 + } 1.114 + 1.115 + /** 1.116 + * Converts a floating point value to an integral type in a safe and 1.117 + * platform agnostic way. The following program demonstrates the kinds 1.118 + * of ways things can go wrong depending on the CPU architecture you're 1.119 + * compiling for: 1.120 + * 1.121 + * #include <stdio.h> 1.122 + * volatile float r; 1.123 + * int main() 1.124 + * { 1.125 + * unsigned int q; 1.126 + * r = 1e100; 1.127 + * q = r; 1.128 + * printf("%f %d\n", r, q); 1.129 + * r = -1e100; 1.130 + * q = r; 1.131 + * printf("%f %d\n", r, q); 1.132 + * r = 1e15; 1.133 + * q = r; 1.134 + * printf("%f %x\n", r, q); 1.135 + * r = 0/0.; 1.136 + * q = r; 1.137 + * printf("%f %d\n", r, q); 1.138 + * } 1.139 + * 1.140 + * This program, when compiled for unsigned int, generates the following 1.141 + * results depending on the architecture: 1.142 + * 1.143 + * x86 and x86-64 1.144 + * --- 1.145 + * inf 0 1.146 + * -inf 0 1.147 + * 999999995904.000000 -727384064 d4a50000 1.148 + * nan 0 1.149 + * 1.150 + * ARM 1.151 + * --- 1.152 + * inf -1 1.153 + * -inf 0 1.154 + * 999999995904.000000 -1 1.155 + * nan 0 1.156 + * 1.157 + * When compiled for int, this program generates the following results: 1.158 + * 1.159 + * x86 and x86-64 1.160 + * --- 1.161 + * inf -2147483648 1.162 + * -inf -2147483648 1.163 + * 999999995904.000000 -2147483648 1.164 + * nan -2147483648 1.165 + * 1.166 + * ARM 1.167 + * --- 1.168 + * inf 2147483647 1.169 + * -inf -2147483648 1.170 + * 999999995904.000000 2147483647 1.171 + * nan 0 1.172 + * 1.173 + * Note that the caller is responsible to make sure that the value 1.174 + * passed to this function is not a NaN. This function will abort if 1.175 + * it sees a NaN. 1.176 + */ 1.177 + template <typename IntType, typename FloatType> 1.178 + IntType TruncateFloatToInt(FloatType f) 1.179 + { 1.180 + using namespace std; 1.181 + 1.182 + static_assert(mozilla::IsIntegral<IntType>::value == true, 1.183 + "IntType must be an integral type"); 1.184 + static_assert(mozilla::IsFloatingPoint<FloatType>::value == true, 1.185 + "FloatType must be a floating point type"); 1.186 + 1.187 + if (f != f) { 1.188 + // It is the responsibility of the caller to deal with NaN values. 1.189 + // If we ever get to this point, we have a serious bug to fix. 1.190 + NS_RUNTIMEABORT("We should never see a NaN here"); 1.191 + } 1.192 + 1.193 + if (f > FloatType(numeric_limits<IntType>::max())) { 1.194 + // If the floating point value is outside of the range of maximum 1.195 + // integral value for this type, just clamp to the maximum value. 1.196 + return numeric_limits<IntType>::max(); 1.197 + } 1.198 + 1.199 + if (f < FloatType(numeric_limits<IntType>::min())) { 1.200 + // If the floating point value is outside of the range of minimum 1.201 + // integral value for this type, just clamp to the minimum value. 1.202 + return numeric_limits<IntType>::min(); 1.203 + } 1.204 + 1.205 + // Otherwise, this conversion must be well defined. 1.206 + return IntType(f); 1.207 + } 1.208 + 1.209 + void Shutdown(); 1.210 + 1.211 + int 1.212 + SpeexResamplerProcess(SpeexResamplerState* aResampler, 1.213 + uint32_t aChannel, 1.214 + const float* aIn, uint32_t* aInLen, 1.215 + float* aOut, uint32_t* aOutLen); 1.216 + 1.217 + int 1.218 + SpeexResamplerProcess(SpeexResamplerState* aResampler, 1.219 + uint32_t aChannel, 1.220 + const int16_t* aIn, uint32_t* aInLen, 1.221 + float* aOut, uint32_t* aOutLen); 1.222 + 1.223 + int 1.224 + SpeexResamplerProcess(SpeexResamplerState* aResampler, 1.225 + uint32_t aChannel, 1.226 + const int16_t* aIn, uint32_t* aInLen, 1.227 + int16_t* aOut, uint32_t* aOutLen); 1.228 + } 1.229 + 1.230 +} 1.231 +} 1.232 + 1.233 +#endif 1.234 +