// This is the 'final' version of the AlmostEqualUlps function. // The optional checks are included for completeness, but in many // cases they are not necessary, or even not desirable. bool AlmostEqualUlpsFinal(float A, float B, int maxUlps) { // There are several optional checks that you can do, depending // on what behavior you want from your floating point comparisons. // These checks should not be necessary and they are included // mainly for completeness. #ifdef INFINITYCHECK // If A or B are infinity (positive or negative) then // only return true if they are exactly equal to each other - // that is, if they are both infinities of the same sign. // This check is only needed if you will be generating // infinities and you don't want them 'close' to numbers // near FLT_MAX. if (IsInfinite(A) || IsInfinite(B)) return A == B; #endif #ifdef NANCHECK // If A or B are a NAN, return false. NANs are equal to nothing, // not even themselves. // This check is only needed if you will be generating NANs // and you use a maxUlps greater than 4 million or you want to // ensure that a NAN does not equal itself. if (IsNan(A) || IsNan(B)) return false; #endif #ifdef SIGNCHECK // After adjusting floats so their representations are lexicographically // ordered as twos-complement integers a very small positive number // will compare as 'close' to a very small negative number. If this is // not desireable, and if you are on a platform that supports // subnormals (which is the only place the problem can show up) then // you need this check. // The check for A == B is because zero and negative zero have different // signs but are equal to each other. if (Sign(A) != Sign(B)) return A == B; #endif int aInt = *(int*)&A; // Make aInt lexicographically ordered as a twos-complement int if (aInt < 0) aInt = 0x80000000 - aInt; // Make bInt lexicographically ordered as a twos-complement int int bInt = *(int*)&B; if (bInt < 0) bInt = 0x80000000 - bInt; // Now we can compare aInt and bInt to find out how far apart A and B // are. int intDiff = abs(aInt - bInt); if (intDiff <= maxUlps) return true; return false; }
Value Iterator::FindMinMaxIndices(Environment &env, bool maxFlag) { Signal &sig = env.GetSignal(); if (IsInfinite()) { SetError_InfiniteNotAllowed(sig); return Value::Nil; } Value valueHit; if (!Next(env, valueHit)) return Value::Nil; Value result; int idxHit = GetIndexCur(); Object_list *pObjListResult = result.InitAsList(env); pObjListResult->Add(Value(idxHit)); Value value; while (Next(env, value)) { int cmp = Value::Compare(env, valueHit, value); if (sig.IsSignalled()) return Value::Nil; if (maxFlag) cmp = -cmp; if (cmp > 0) { int idxHit = GetIndexCur(); valueHit = value; pObjListResult->Clear(); pObjListResult->Add(Value(idxHit)); } else if (cmp == 0) { int idxHit = GetIndexCur(); pObjListResult->Add(Value(static_cast<Number>(idxHit))); } } if (sig.IsSignalled()) return Value::Nil; return result; }
Value Iterator::Reduce(Environment &env, Value valueAccum, const Function *pFuncBlock) { Signal &sig = env.GetSignal(); if (IsInfinite()) { SetError_InfiniteNotAllowed(sig); return Value::Nil; } Value value; while (Next(env, value)) { AutoPtr<Argument> pArgSub(new Argument(pFuncBlock)); if (!pArgSub->StoreValue(env, value, valueAccum)) return Value::Nil; Value result = pFuncBlock->Eval(env, *pArgSub); if (!sig.IsSignalled()) { // nothing to do } else if (sig.IsBreak()) { result = sig.GetValue(); sig.ClearSignal(); if (result.IsValid()) return result; return valueAccum; } else if (sig.IsContinue()) { result = sig.GetValue(); sig.ClearSignal(); if (result.IsInvalid()) continue; } else if (sig.IsReturn()) { return Value::Nil; } else { return Value::Nil; } valueAccum = result; } if (sig.IsSignalled()) return Value::Nil; return valueAccum; }
Value Iterator::ToList(Environment &env, bool alwaysListFlag, bool excludeNilFlag) { Signal &sig = env.GetSignal(); if (IsInfinite()) { SetError_InfiniteNotAllowed(sig); return Value::Nil; } Value result; Object_list *pObjList = nullptr; size_t cnt = 0; Value value; if (alwaysListFlag) { pObjList = result.InitAsList(env); } while (Next(env, value)) { if (pObjList == nullptr && !value.IsUndefined()) { pObjList = result.InitAsList(env, cnt, Value::Nil); } if (value.IsValid()) { if (pObjList == nullptr) { pObjList = result.InitAsList(env, cnt, Value::Nil); } pObjList->Add(value); } else if (excludeNilFlag) { // nothing to do } else if (pObjList != nullptr) { pObjList->Add(value); } cnt++; } if (sig.IsSignalled()) return Value::Nil; return result; }
size_t Iterator::Count(Environment &env, const Value &criteria) { Signal &sig = env.GetSignal(); if (IsInfinite()) { SetError_InfiniteNotAllowed(sig); return 0; } size_t cnt = 0; if (criteria.Is_function()) { const Function *pFunc = criteria.GetFunction(); Value value; while (Next(env, value)) { AutoPtr<Argument> pArg(new Argument(pFunc)); if (!pArg->StoreValue(env, value)) return 0; Value valueFlag = pFunc->Eval(env, *pArg); if (sig.IsSignalled()) return 0; if (valueFlag.GetBoolean()) cnt++; } if (sig.IsSignalled()) return 0; } else { Value value; while (Next(env, value)) { int cmp = Value::Compare(env, value, criteria); if (sig.IsSignalled()) return 0; if (cmp == 0) cnt++; } } return cnt; }
void SourceBuffer::DoRangeRemoval(double aStart, double aEnd) { MSE_DEBUG("DoRangeRemoval(%f, %f)", aStart, aEnd); if (mTrackBuffer && !IsInfinite(aStart)) { mTrackBuffer->RangeRemoval(media::Microseconds::FromSeconds(aStart), media::Microseconds::FromSeconds(aEnd)); } }
Value Iterator::StandardDeviation(Environment &env, size_t &cnt, bool populationFlag) { Signal &sig = env.GetSignal(); if (IsInfinite()) { SetError_InfiniteNotAllowed(sig); return Value::Nil; } Value valueVar = Clone()->Variance(env, cnt, populationFlag); if (!valueVar.Is_number()) return Value::Nil; return Value(::sqrt(valueVar.GetNumber())); }
bool Iterator::Consume(Environment &env) { Signal &sig = env.GetSignal(); if (IsInfinite()) { SetError_InfiniteNotAllowed(sig); return false; } Value value; while (Next(env, value)) ; return !sig.IsSignalled(); }
size_t Iterator::FindTrue(Environment &env, Value &value) { Signal &sig = env.GetSignal(); if (IsInfinite()) { SetError_InfiniteNotAllowed(sig); return 0; } while (Next(env, value)) { if (value.GetBoolean()) return GetIndexCur(); } return InvalidSize; }
size_t Iterator::Find(Environment &env, const Value &criteria, Value &value) { Signal &sig = env.GetSignal(); if (criteria.Is_function()) { if (IsInfinite()) { SetError_InfiniteNotAllowed(sig); return InvalidSize; } const Function *pFunc = criteria.GetFunction(); while (Next(env, value)) { AutoPtr<Argument> pArg(new Argument(pFunc)); if (!pArg->StoreValue(env, value)) return InvalidSize; Value valueFlag = pFunc->Eval(env, *pArg); if (sig.IsSignalled()) return InvalidSize; if (valueFlag.GetBoolean()) return GetIndexCur(); } if (sig.IsSignalled()) return InvalidSize; } else if (criteria.Is_list() || criteria.Is_iterator()) { AutoPtr<Iterator> pIteratorCriteria(criteria.CreateIterator(sig)); if (sig.IsSignalled()) return InvalidSize; if (IsInfinite() && pIteratorCriteria->IsInfinite()) { SetError_InfiniteNotAllowed(sig); return InvalidSize; } while (Next(env, value)) { Value valueCriteria; if (!pIteratorCriteria->Next(env, valueCriteria)) break; if (valueCriteria.GetBoolean()) return GetIndexCur(); } return InvalidSize; } else { while (Next(env, value)) { //int cmp = Value::Compare(env, value, criteria); //if (sig.IsSignalled()) return InvalidSize; //if (cmp == 0) return GetIndexCur(); if (value.Is(criteria)) return GetIndexCur(); } } return InvalidSize; }
size_t Iterator::CountTrue(Environment &env) { Signal &sig = env.GetSignal(); if (IsInfinite()) { SetError_InfiniteNotAllowed(sig); return 0; } size_t cnt = 0; Value value; while (Next(env, value)) { if (value.GetBoolean()) cnt++; } return cnt; }
size_t Iterator::GetLengthEx(Environment &env) { if (IsFinitePredictable()) return GetLength(); Signal &sig = env.GetSignal(); if (IsInfinite()) { SetError_InfiniteNotAllowed(sig); return 0; } size_t len = 0; AutoPtr<Iterator> pIterator(Clone()); Value value; for ( ; pIterator->Next(env, value); len++) ; return sig.IsSignalled()? 0 : len; }
bool Iterator::DoesContain(Environment &env, const Value &value) { Signal &sig = env.GetSignal(); if (IsInfinite()) { SetError_InfiniteNotAllowed(sig); return false; } Value valueToFind; while (Next(env, valueToFind)) { int cmp = Value::Compare(env, value, valueToFind); if (sig.IsSignalled()) return false; if (cmp == 0) return true; } return false; }
Value Iterator::Or(Environment &env) { Signal &sig = env.GetSignal(); if (IsInfinite()) { SetError_InfiniteNotAllowed(sig); return Value::Nil; } Value value; if (!Next(env, value)) return Value::Nil; if (value.GetBoolean()) return Value(true); while (Next(env, value)) { if (value.GetBoolean()) return Value(true); } if (sig.IsSignalled()) return Value::Nil; return Value(false); }
Binary Iterator::Joinb(Environment &env) { Signal &sig = env.GetSignal(); Binary rtn; Value value; if (IsInfinite()) { SetError_InfiniteNotAllowed(sig); return rtn; } while (Next(env, value)) { if (!value.Is_binary()) { sig.SetError(ERR_ValueError, "invalid value type"); return ""; } rtn += value.GetBinary(); } return rtn; }
String Iterator::Join(Environment &env, const char *sep) { Signal &sig = env.GetSignal(); String rtn; Value value; if (IsInfinite()) { SetError_InfiniteNotAllowed(sig); return rtn; } if (Next(env, value)) { rtn += value.ToString(false); while (Next(env, value)) { rtn += sep; rtn += value.ToString(false); } } return rtn; }
Value Iterator::Average(Environment &env, size_t &cnt) { Signal &sig = env.GetSignal(); if (IsInfinite()) { SetError_InfiniteNotAllowed(sig); return Value::Nil; } Value valueSum = Clone()->Sum(env, cnt); if (valueSum.IsInvalid()) { return Value::Nil; } else if (valueSum.Is_number()) { return Value(valueSum.GetNumber() / static_cast<Number>(cnt)); } else if (valueSum.Is_complex()) { return Value(valueSum.GetComplex() / static_cast<Number>(cnt)); } else { const Operator *pOperatorDiv = env.GetOperator(OPTYPE_Div); return pOperatorDiv->EvalBinary(env, valueSum, Value(cnt), FLAG_None); } }
Value Iterator::FindMinMax(Environment &env, bool maxFlag) { Signal &sig = env.GetSignal(); if (IsInfinite()) { SetError_InfiniteNotAllowed(sig); return Value::Nil; } Value valueHit; if (!Next(env, valueHit)) return Value::Nil; Value value; while (Next(env, value)) { int cmp = Value::Compare(env, valueHit, value); if (sig.IsSignalled()) return Value::Nil; if (maxFlag) cmp = -cmp; if (cmp > 0) { valueHit = value; } } if (sig.IsSignalled()) return Value::Nil; return valueHit; }
void DynamicsCompressorKernel::process(float* sourceChannels[], float* destinationChannels[], unsigned numberOfChannels, unsigned framesToProcess, float dbThreshold, float dbKnee, float ratio, float attackTime, float releaseTime, float preDelayTime, float dbPostGain, float effectBlend, /* equal power crossfade */ float releaseZone1, float releaseZone2, float releaseZone3, float releaseZone4 ) { MOZ_ASSERT(m_preDelayBuffers.Length() == numberOfChannels); float sampleRate = this->sampleRate(); float dryMix = 1 - effectBlend; float wetMix = effectBlend; float k = updateStaticCurveParameters(dbThreshold, dbKnee, ratio); // Makeup gain. float fullRangeGain = saturate(1, k); float fullRangeMakeupGain = 1 / fullRangeGain; // Empirical/perceptual tuning. fullRangeMakeupGain = powf(fullRangeMakeupGain, 0.6f); float masterLinearGain = WebAudioUtils::ConvertDecibelsToLinear(dbPostGain) * fullRangeMakeupGain; // Attack parameters. attackTime = max(0.001f, attackTime); float attackFrames = attackTime * sampleRate; // Release parameters. float releaseFrames = sampleRate * releaseTime; // Detector release time. float satReleaseTime = 0.0025f; float satReleaseFrames = satReleaseTime * sampleRate; // Create a smooth function which passes through four points. // Polynomial of the form // y = a + b*x + c*x^2 + d*x^3 + e*x^4; float y1 = releaseFrames * releaseZone1; float y2 = releaseFrames * releaseZone2; float y3 = releaseFrames * releaseZone3; float y4 = releaseFrames * releaseZone4; // All of these coefficients were derived for 4th order polynomial curve fitting where the y values // match the evenly spaced x values as follows: (y1 : x == 0, y2 : x == 1, y3 : x == 2, y4 : x == 3) float kA = 0.9999999999999998f*y1 + 1.8432219684323923e-16f*y2 - 1.9373394351676423e-16f*y3 + 8.824516011816245e-18f*y4; float kB = -1.5788320352845888f*y1 + 2.3305837032074286f*y2 - 0.9141194204840429f*y3 + 0.1623677525612032f*y4; float kC = 0.5334142869106424f*y1 - 1.272736789213631f*y2 + 0.9258856042207512f*y3 - 0.18656310191776226f*y4; float kD = 0.08783463138207234f*y1 - 0.1694162967925622f*y2 + 0.08588057951595272f*y3 - 0.00429891410546283f*y4; float kE = -0.042416883008123074f*y1 + 0.1115693827987602f*y2 - 0.09764676325265872f*y3 + 0.028494263462021576f*y4; // x ranges from 0 -> 3 0 1 2 3 // -15 -10 -5 0db // y calculates adaptive release frames depending on the amount of compression. setPreDelayTime(preDelayTime); const int nDivisionFrames = 32; const int nDivisions = framesToProcess / nDivisionFrames; unsigned frameIndex = 0; for (int i = 0; i < nDivisions; ++i) { // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Calculate desired gain // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Fix gremlins. if (IsNaN(m_detectorAverage)) m_detectorAverage = 1; if (IsInfinite(m_detectorAverage)) m_detectorAverage = 1; float desiredGain = m_detectorAverage; // Pre-warp so we get desiredGain after sin() warp below. float scaledDesiredGain = asinf(desiredGain) / (0.5f * M_PI); // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Deal with envelopes // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // envelopeRate is the rate we slew from current compressor level to the desired level. // The exact rate depends on if we're attacking or releasing and by how much. float envelopeRate; bool isReleasing = scaledDesiredGain > m_compressorGain; // compressionDiffDb is the difference between current compression level and the desired level. float compressionDiffDb = WebAudioUtils::ConvertLinearToDecibels(m_compressorGain / scaledDesiredGain, -1000.0f); if (isReleasing) { // Release mode - compressionDiffDb should be negative dB m_maxAttackCompressionDiffDb = -1; // Fix gremlins. if (IsNaN(compressionDiffDb)) compressionDiffDb = -1; if (IsInfinite(compressionDiffDb)) compressionDiffDb = -1; // Adaptive release - higher compression (lower compressionDiffDb) releases faster. // Contain within range: -12 -> 0 then scale to go from 0 -> 3 float x = compressionDiffDb; x = max(-12.0f, x); x = min(0.0f, x); x = 0.25f * (x + 12); // Compute adaptive release curve using 4th order polynomial. // Normal values for the polynomial coefficients would create a monotonically increasing function. float x2 = x * x; float x3 = x2 * x; float x4 = x2 * x2; float releaseFrames = kA + kB * x + kC * x2 + kD * x3 + kE * x4; #define kSpacingDb 5 float dbPerFrame = kSpacingDb / releaseFrames; envelopeRate = WebAudioUtils::ConvertDecibelsToLinear(dbPerFrame); } else { // Attack mode - compressionDiffDb should be positive dB // Fix gremlins. if (IsNaN(compressionDiffDb)) compressionDiffDb = 1; if (IsInfinite(compressionDiffDb)) compressionDiffDb = 1; // As long as we're still in attack mode, use a rate based off // the largest compressionDiffDb we've encountered so far. if (m_maxAttackCompressionDiffDb == -1 || m_maxAttackCompressionDiffDb < compressionDiffDb) m_maxAttackCompressionDiffDb = compressionDiffDb; float effAttenDiffDb = max(0.5f, m_maxAttackCompressionDiffDb); float x = 0.25f / effAttenDiffDb; envelopeRate = 1 - powf(x, 1 / attackFrames); } // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Inner loop - calculate shaped power average - apply compression. // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ { int preDelayReadIndex = m_preDelayReadIndex; int preDelayWriteIndex = m_preDelayWriteIndex; float detectorAverage = m_detectorAverage; float compressorGain = m_compressorGain; int loopFrames = nDivisionFrames; while (loopFrames--) { float compressorInput = 0; // Predelay signal, computing compression amount from un-delayed version. for (unsigned i = 0; i < numberOfChannels; ++i) { float* delayBuffer = m_preDelayBuffers[i].get(); float undelayedSource = sourceChannels[i][frameIndex]; delayBuffer[preDelayWriteIndex] = undelayedSource; float absUndelayedSource = undelayedSource > 0 ? undelayedSource : -undelayedSource; if (compressorInput < absUndelayedSource) compressorInput = absUndelayedSource; } // Calculate shaped power on undelayed input. float scaledInput = compressorInput; float absInput = scaledInput > 0 ? scaledInput : -scaledInput; // Put through shaping curve. // This is linear up to the threshold, then enters a "knee" portion followed by the "ratio" portion. // The transition from the threshold to the knee is smooth (1st derivative matched). // The transition from the knee to the ratio portion is smooth (1st derivative matched). float shapedInput = saturate(absInput, k); float attenuation = absInput <= 0.0001f ? 1 : shapedInput / absInput; float attenuationDb = -WebAudioUtils::ConvertLinearToDecibels(attenuation, -1000.0f); attenuationDb = max(2.0f, attenuationDb); float dbPerFrame = attenuationDb / satReleaseFrames; float satReleaseRate = WebAudioUtils::ConvertDecibelsToLinear(dbPerFrame) - 1; bool isRelease = (attenuation > detectorAverage); float rate = isRelease ? satReleaseRate : 1; detectorAverage += (attenuation - detectorAverage) * rate; detectorAverage = min(1.0f, detectorAverage); // Fix gremlins. if (IsNaN(detectorAverage)) detectorAverage = 1; if (IsInfinite(detectorAverage)) detectorAverage = 1; // Exponential approach to desired gain. if (envelopeRate < 1) { // Attack - reduce gain to desired. compressorGain += (scaledDesiredGain - compressorGain) * envelopeRate; } else { // Release - exponentially increase gain to 1.0 compressorGain *= envelopeRate; compressorGain = min(1.0f, compressorGain); } // Warp pre-compression gain to smooth out sharp exponential transition points. float postWarpCompressorGain = sinf(0.5f * M_PI * compressorGain); // Calculate total gain using master gain and effect blend. float totalGain = dryMix + wetMix * masterLinearGain * postWarpCompressorGain; // Calculate metering. float dbRealGain = 20 * log10(postWarpCompressorGain); if (dbRealGain < m_meteringGain) m_meteringGain = dbRealGain; else m_meteringGain += (dbRealGain - m_meteringGain) * m_meteringReleaseK; // Apply final gain. for (unsigned i = 0; i < numberOfChannels; ++i) { float* delayBuffer = m_preDelayBuffers[i].get(); destinationChannels[i][frameIndex] = delayBuffer[preDelayReadIndex] * totalGain; } frameIndex++; preDelayReadIndex = (preDelayReadIndex + 1) & MaxPreDelayFramesMask; preDelayWriteIndex = (preDelayWriteIndex + 1) & MaxPreDelayFramesMask; } // Locals back to member variables. m_preDelayReadIndex = preDelayReadIndex; m_preDelayWriteIndex = preDelayWriteIndex; m_detectorAverage = DenormalDisabler::flushDenormalFloatToZero(detectorAverage); m_compressorGain = DenormalDisabler::flushDenormalFloatToZero(compressorGain); } } }
Value Iterator::Variance(Environment &env, size_t &cnt, bool populationFlag) { Signal &sig = env.GetSignal(); if (IsInfinite()) { SetError_InfiniteNotAllowed(sig); return Value::Nil; } // this doesn't use a variance calculation formula V(x) = E(x**2) - E(x)**2 // to minimize calculation error. Value valueAve = Clone()->Average(env, cnt); if (!valueAve.IsNumberOrComplex()) return Value::Nil; Number denom = static_cast<Number>((cnt <= 1)? 1 : populationFlag? cnt : cnt - 1); Value value; if (!Next(env, value)) return Value::Nil; if (value.Is_number() && valueAve.Is_number()) { Number result; Number average = valueAve.GetNumber(); do { Number tmp = value.GetNumber() - average; result = tmp * tmp; } while (0); while (Next(env, value)) { if (value.Is_number()) { Number tmp = value.GetNumber() - average; result += tmp * tmp; } else if (value.Is_complex()) { while (Next(env, value)) { if (value.IsNumberOrComplex()) { Complex tmp = value.GetComplex() - average; result += std::norm(tmp); } else { SetError_InvalidDataTypeOfElement(sig); return Value::Nil; } } } else { SetError_InvalidDataTypeOfElement(sig); return Value::Nil; } } if (sig.IsSignalled()) return Value::Nil; return Value(result / denom); } else if (value.IsNumberOrComplex()) { Number result; Complex average = valueAve.GetComplex(); do { Complex tmp = value.GetComplex() - average; result = std::norm(tmp); } while (0); while (Next(env, value)) { if (value.IsNumberOrComplex()) { Complex tmp = value.GetComplex() - average; result += std::norm(tmp); } else { SetError_InvalidDataTypeOfElement(sig); return Value::Nil; } } if (sig.IsSignalled()) return Value::Nil; return Value(result / denom); } else { SetError_InvalidDataTypeOfElement(sig); return Value::Nil; } }