Line data Source code
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 "mozilla/TypeTraits.h"
13 : #include "mozilla/FloatingPoint.h"
14 : #include "MediaSegment.h"
15 :
16 : // Forward declaration
17 : typedef struct SpeexResamplerState_ SpeexResamplerState;
18 :
19 : namespace mozilla {
20 :
21 : class AudioNodeStream;
22 :
23 : extern LazyLogModule gWebAudioAPILog;
24 : #define WEB_AUDIO_API_LOG(...) \
25 : MOZ_LOG(gWebAudioAPILog, LogLevel::Debug, (__VA_ARGS__))
26 :
27 : namespace dom {
28 :
29 : struct AudioTimelineEvent;
30 :
31 : namespace WebAudioUtils {
32 : // 32 is the minimum required by the spec for createBuffer() and
33 : // createScriptProcessor() and matches what is used by Blink. The limit
34 : // protects against large memory allocations.
35 : const size_t MaxChannelCount = 32;
36 : // AudioContext::CreateBuffer() "must support sample-rates in at least the
37 : // range 22050 to 96000."
38 : const uint32_t MinSampleRate = 8000;
39 : const uint32_t MaxSampleRate = 192000;
40 :
41 : inline bool FuzzyEqual(float v1, float v2)
42 : {
43 : using namespace std;
44 : return fabsf(v1 - v2) < 1e-7f;
45 : }
46 0 : inline bool FuzzyEqual(double v1, double v2)
47 : {
48 : using namespace std;
49 0 : return fabs(v1 - v2) < 1e-7;
50 : }
51 :
52 : /**
53 : * Computes an exponential smoothing rate for a time based variable
54 : * over aDuration seconds.
55 : */
56 0 : inline double ComputeSmoothingRate(double aDuration, double aSampleRate)
57 : {
58 0 : return 1.0 - std::exp(-1.0 / (aDuration * aSampleRate));
59 : }
60 :
61 : /**
62 : * Converts an AudioTimelineEvent's floating point time values to tick values
63 : * with respect to a destination AudioNodeStream.
64 : *
65 : * This needs to be called for each AudioTimelineEvent that gets sent to an
66 : * AudioNodeEngine, on the engine side where the AudioTimlineEvent is
67 : * received. This means that such engines need to be aware of their
68 : * destination streams as well.
69 : */
70 : void ConvertAudioTimelineEventToTicks(AudioTimelineEvent& aEvent,
71 : AudioNodeStream* aDest);
72 :
73 : /**
74 : * Converts a linear value to decibels. Returns aMinDecibels if the linear
75 : * value is 0.
76 : */
77 0 : inline float ConvertLinearToDecibels(float aLinearValue, float aMinDecibels)
78 : {
79 0 : return aLinearValue ? 20.0f * std::log10(aLinearValue) : aMinDecibels;
80 : }
81 :
82 : /**
83 : * Converts a decibel value to a linear value.
84 : */
85 0 : inline float ConvertDecibelsToLinear(float aDecibels)
86 : {
87 0 : return std::pow(10.0f, 0.05f * aDecibels);
88 : }
89 :
90 : /**
91 : * Converts a decibel to a linear value.
92 : */
93 : inline float ConvertDecibelToLinear(float aDecibel)
94 : {
95 : return std::pow(10.0f, 0.05f * aDecibel);
96 : }
97 :
98 0 : inline void FixNaN(double& aDouble)
99 : {
100 0 : if (IsNaN(aDouble) || IsInfinite(aDouble)) {
101 0 : aDouble = 0.0;
102 : }
103 0 : }
104 :
105 0 : inline double DiscreteTimeConstantForSampleRate(double timeConstant, double sampleRate)
106 : {
107 0 : return 1.0 - std::exp(-1.0 / (sampleRate * timeConstant));
108 : }
109 :
110 0 : inline bool IsTimeValid(double aTime)
111 : {
112 0 : return aTime >= 0 && aTime <= (MEDIA_TIME_MAX >> TRACK_RATE_MAX_BITS);
113 : }
114 :
115 : /**
116 : * Converts a floating point value to an integral type in a safe and
117 : * platform agnostic way. The following program demonstrates the kinds
118 : * of ways things can go wrong depending on the CPU architecture you're
119 : * compiling for:
120 : *
121 : * #include <stdio.h>
122 : * volatile float r;
123 : * int main()
124 : * {
125 : * unsigned int q;
126 : * r = 1e100;
127 : * q = r;
128 : * printf("%f %d\n", r, q);
129 : * r = -1e100;
130 : * q = r;
131 : * printf("%f %d\n", r, q);
132 : * r = 1e15;
133 : * q = r;
134 : * printf("%f %x\n", r, q);
135 : * r = 0/0.;
136 : * q = r;
137 : * printf("%f %d\n", r, q);
138 : * }
139 : *
140 : * This program, when compiled for unsigned int, generates the following
141 : * results depending on the architecture:
142 : *
143 : * x86 and x86-64
144 : * ---
145 : * inf 0
146 : * -inf 0
147 : * 999999995904.000000 -727384064 d4a50000
148 : * nan 0
149 : *
150 : * ARM
151 : * ---
152 : * inf -1
153 : * -inf 0
154 : * 999999995904.000000 -1
155 : * nan 0
156 : *
157 : * When compiled for int, this program generates the following results:
158 : *
159 : * x86 and x86-64
160 : * ---
161 : * inf -2147483648
162 : * -inf -2147483648
163 : * 999999995904.000000 -2147483648
164 : * nan -2147483648
165 : *
166 : * ARM
167 : * ---
168 : * inf 2147483647
169 : * -inf -2147483648
170 : * 999999995904.000000 2147483647
171 : * nan 0
172 : *
173 : * Note that the caller is responsible to make sure that the value
174 : * passed to this function is not a NaN. This function will abort if
175 : * it sees a NaN.
176 : */
177 : template <typename IntType, typename FloatType>
178 0 : IntType TruncateFloatToInt(FloatType f)
179 : {
180 : using namespace std;
181 :
182 : static_assert(mozilla::IsIntegral<IntType>::value == true,
183 : "IntType must be an integral type");
184 : static_assert(mozilla::IsFloatingPoint<FloatType>::value == true,
185 : "FloatType must be a floating point type");
186 :
187 0 : if (mozilla::IsNaN(f)) {
188 : // It is the responsibility of the caller to deal with NaN values.
189 : // If we ever get to this point, we have a serious bug to fix.
190 0 : MOZ_CRASH("We should never see a NaN here");
191 : }
192 :
193 : // If the floating point value is outside of the range of maximum
194 : // integral value for this type, just clamp to the maximum value.
195 : // The equality case must also return max() due to loss of precision when
196 : // converting max() to float.
197 0 : if (f >= FloatType(numeric_limits<IntType>::max())) {
198 0 : return numeric_limits<IntType>::max();
199 : }
200 :
201 0 : if (f <= FloatType(numeric_limits<IntType>::min())) {
202 : // If the floating point value is outside of the range of minimum
203 : // integral value for this type, just clamp to the minimum value.
204 0 : return numeric_limits<IntType>::min();
205 : }
206 :
207 : // Otherwise, this conversion must be well defined.
208 0 : return IntType(f);
209 : }
210 :
211 : void Shutdown();
212 :
213 : int
214 : SpeexResamplerProcess(SpeexResamplerState* aResampler,
215 : uint32_t aChannel,
216 : const float* aIn, uint32_t* aInLen,
217 : float* aOut, uint32_t* aOutLen);
218 :
219 : int
220 : SpeexResamplerProcess(SpeexResamplerState* aResampler,
221 : uint32_t aChannel,
222 : const int16_t* aIn, uint32_t* aInLen,
223 : float* aOut, uint32_t* aOutLen);
224 :
225 : int
226 : SpeexResamplerProcess(SpeexResamplerState* aResampler,
227 : uint32_t aChannel,
228 : const int16_t* aIn, uint32_t* aInLen,
229 : int16_t* aOut, uint32_t* aOutLen);
230 :
231 : void
232 : LogToDeveloperConsole(uint64_t aWindowID, const char* aKey);
233 :
234 : } // namespace WebAudioUtils
235 :
236 : } // namespace dom
237 : } // namespace mozilla
238 :
239 : #endif
240 :
|