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/. */
7 #ifndef WebAudioUtils_h_
8 #define WebAudioUtils_h_
12 #include <type_traits>
13 #include "mozilla/FloatingPoint.h"
14 #include "mozilla/Logging.h"
15 #include "MediaSegment.h"
17 // Forward declaration
18 typedef struct SpeexResamplerState_ SpeexResamplerState
;
24 extern LazyLogModule gWebAudioAPILog
;
25 #define WEB_AUDIO_API_LOG(...) \
26 MOZ_LOG(gWebAudioAPILog, LogLevel::Debug, (__VA_ARGS__))
30 struct AudioTimelineEvent
;
32 namespace WebAudioUtils
{
33 // 32 is the minimum required by the spec for createBuffer() and
34 // createScriptProcessor() and matches what is used by Blink. The limit
35 // protects against large memory allocations.
36 const size_t MaxChannelCount
= 32;
37 // AudioContext::CreateBuffer() "must support sample-rates in at least the
38 // range 22050 to 96000."
39 const uint32_t MinSampleRate
= 8000;
40 const uint32_t MaxSampleRate
= 192000;
42 inline bool FuzzyEqual(float v1
, float v2
) { return fabsf(v1
- v2
) < 1e-7f
; }
43 inline bool FuzzyEqual(double v1
, double v2
) { return fabs(v1
- v2
) < 1e-7; }
46 * Converts an AudioTimelineEvent's floating point time values to tick values
47 * with respect to a destination AudioNodeTrack.
49 * This needs to be called for each AudioTimelineEvent that gets sent to an
50 * AudioNodeEngine, on the engine side where the AudioTimlineEvent is
51 * received. This means that such engines need to be aware of their
52 * destination tracks as well.
54 void ConvertAudioTimelineEventToTicks(AudioTimelineEvent
& aEvent
,
55 AudioNodeTrack
* aDest
);
58 * Converts a linear value to decibels. Returns aMinDecibels if the linear
61 inline float ConvertLinearToDecibels(float aLinearValue
, float aMinDecibels
) {
62 return aLinearValue
? 20.0f
* std::log10(aLinearValue
) : aMinDecibels
;
66 * Converts a decibel value to a linear value.
68 inline float ConvertDecibelsToLinear(float aDecibels
) {
69 return std::pow(10.0f
, 0.05f
* aDecibels
);
73 * Converts a decibel to a linear value.
75 inline float ConvertDecibelToLinear(float aDecibel
) {
76 return std::pow(10.0f
, 0.05f
* aDecibel
);
79 inline void FixNaN(double& aDouble
) {
80 if (std::isnan(aDouble
) || std::isinf(aDouble
)) {
85 inline double DiscreteTimeConstantForSampleRate(double timeConstant
,
87 return 1.0 - std::exp(-1.0 / (sampleRate
* timeConstant
));
90 inline bool IsTimeValid(double aTime
) {
91 return aTime
>= 0 && aTime
<= (MEDIA_TIME_MAX
>> TRACK_RATE_MAX_BITS
);
95 * Converts a floating point value to an integral type in a safe and
96 * platform agnostic way. The following program demonstrates the kinds
97 * of ways things can go wrong depending on the CPU architecture you're
107 * printf("%f %d\n", r, q);
110 * printf("%f %d\n", r, q);
113 * printf("%f %x\n", r, q);
116 * printf("%f %d\n", r, q);
119 * This program, when compiled for unsigned int, generates the following
120 * results depending on the architecture:
126 * 999999995904.000000 -727384064 d4a50000
133 * 999999995904.000000 -1
136 * When compiled for int, this program generates the following results:
142 * 999999995904.000000 -2147483648
149 * 999999995904.000000 2147483647
152 * Note that the caller is responsible to make sure that the value
153 * passed to this function is not a NaN. This function will abort if
156 template <typename IntType
, typename FloatType
>
157 IntType
TruncateFloatToInt(FloatType f
) {
158 using std::numeric_limits
;
159 static_assert(std::is_integral_v
<IntType
> == true,
160 "IntType must be an integral type");
161 static_assert(std::is_floating_point_v
<FloatType
> == true,
162 "FloatType must be a floating point type");
165 // It is the responsibility of the caller to deal with NaN values.
166 // If we ever get to this point, we have a serious bug to fix.
167 MOZ_CRASH("We should never see a NaN here");
170 // If the floating point value is outside of the range of maximum
171 // integral value for this type, just clamp to the maximum value.
172 // The equality case must also return max() due to loss of precision when
173 // converting max() to float.
174 if (f
>= FloatType(numeric_limits
<IntType
>::max())) {
175 return numeric_limits
<IntType
>::max();
178 if (f
<= FloatType(numeric_limits
<IntType
>::min())) {
179 // If the floating point value is outside of the range of minimum
180 // integral value for this type, just clamp to the minimum value.
181 return numeric_limits
<IntType
>::min();
184 // Otherwise, this conversion must be well defined.
190 int SpeexResamplerProcess(SpeexResamplerState
* aResampler
, uint32_t aChannel
,
191 const float* aIn
, uint32_t* aInLen
, float* aOut
,
194 int SpeexResamplerProcess(SpeexResamplerState
* aResampler
, uint32_t aChannel
,
195 const int16_t* aIn
, uint32_t* aInLen
, float* aOut
,
198 int SpeexResamplerProcess(SpeexResamplerState
* aResampler
, uint32_t aChannel
,
199 const int16_t* aIn
, uint32_t* aInLen
, int16_t* aOut
,
202 void LogToDeveloperConsole(uint64_t aWindowID
, const char* aKey
);
204 } // namespace WebAudioUtils
207 } // namespace mozilla