| @@ -188,7 +188,7 @@ public: | |||
| if (canMoveTransport()) | |||
| setRange ({ newStart, newStart + visibleRange.getLength() }); | |||
| if (wheel.deltaY != 0.0f) | |||
| if (! approximatelyEqual (wheel.deltaY, 0.0f)) | |||
| zoomSlider.setValue (zoomSlider.getValue() - wheel.deltaY); | |||
| repaint(); | |||
| @@ -88,8 +88,8 @@ struct SineWaveVoice : public SynthesiserVoice | |||
| // start a tail-off by setting this flag. The render callback will pick up on | |||
| // this and do a fade out, calling clearCurrentNote() when it's finished. | |||
| if (tailOff == 0.0) // we only need to begin a tail-off if it's not already doing so - the | |||
| tailOff = 1.0; // stopNote method could be called more than once. | |||
| if (approximatelyEqual (tailOff, 0.0)) // we only need to begin a tail-off if it's not already doing so - the | |||
| tailOff = 1.0; // stopNote method could be called more than once. | |||
| } | |||
| else | |||
| { | |||
| @@ -104,7 +104,7 @@ struct SineWaveVoice : public SynthesiserVoice | |||
| void renderNextBlock (AudioBuffer<float>& outputBuffer, int startSample, int numSamples) override | |||
| { | |||
| if (angleDelta != 0.0) | |||
| if (! approximatelyEqual (angleDelta, 0.0)) | |||
| { | |||
| if (tailOff > 0.0) | |||
| { | |||
| @@ -499,8 +499,8 @@ public: | |||
| // start a tail-off by setting this flag. The render callback will pick up on | |||
| // this and do a fade out, calling clearCurrentNote() when it's finished. | |||
| if (tailOff == 0.0) // we only need to begin a tail-off if it's not already doing so - the | |||
| // stopNote method could be called more than once. | |||
| if (approximatelyEqual (tailOff, 0.0)) // we only need to begin a tail-off if it's not already doing so - the | |||
| // stopNote method could be called more than once. | |||
| tailOff = 1.0; | |||
| } | |||
| else | |||
| @@ -530,7 +530,7 @@ public: | |||
| void setCurrentSampleRate (double newRate) override | |||
| { | |||
| if (currentSampleRate != newRate) | |||
| if (! approximatelyEqual (currentSampleRate, newRate)) | |||
| { | |||
| noteStopped (false); | |||
| currentSampleRate = newRate; | |||
| @@ -546,7 +546,7 @@ public: | |||
| int startSample, | |||
| int numSamples) override | |||
| { | |||
| if (phaseDelta != 0.0) | |||
| if (! approximatelyEqual (phaseDelta, 0.0)) | |||
| { | |||
| if (tailOff > 0.0) | |||
| { | |||
| @@ -77,7 +77,7 @@ struct FIRFilterDemoDSP | |||
| void updateParameters() | |||
| { | |||
| if (sampleRate != 0.0) | |||
| if (! approximatelyEqual (sampleRate, 0.0)) | |||
| { | |||
| auto cutoff = static_cast<float> (cutoffParam.getCurrentValue()); | |||
| auto windowingMethod = static_cast<WindowingFunction<float>::WindowingMethod> (typeParam.getCurrentSelectedID() - 1); | |||
| @@ -76,7 +76,7 @@ struct IIRFilterDemoDSP | |||
| void updateParameters() | |||
| { | |||
| if (sampleRate != 0.0) | |||
| if (! approximatelyEqual (sampleRate, 0.0)) | |||
| { | |||
| auto cutoff = static_cast<float> (cutoffParam.getCurrentValue()); | |||
| auto qVal = static_cast<float> (qParam.getCurrentValue()); | |||
| @@ -90,7 +90,7 @@ struct OverdriveDemoDSP | |||
| void updateParameters() | |||
| { | |||
| if (sampleRate != 0.0) | |||
| if (! approximatelyEqual (sampleRate, 0.0)) | |||
| { | |||
| overdrive.get<0>().setGainDecibels (static_cast<float> (inGainParam.getCurrentValue())); | |||
| overdrive.get<4>().setGainDecibels (static_cast<float> (outGainParam.getCurrentValue())); | |||
| @@ -124,7 +124,7 @@ struct SIMDRegisterDemoDSP | |||
| void updateParameters() | |||
| { | |||
| if (sampleRate != 0.0) | |||
| if (! approximatelyEqual (sampleRate, 0.0)) | |||
| { | |||
| auto cutoff = static_cast<float> (cutoffParam.getCurrentValue()); | |||
| auto qVal = static_cast<float> (qParam.getCurrentValue()); | |||
| @@ -74,7 +74,7 @@ struct StateVariableFilterDemoDSP | |||
| void updateParameters() | |||
| { | |||
| if (sampleRate != 0.0) | |||
| if (! approximatelyEqual (sampleRate, 0.0)) | |||
| { | |||
| filter.setCutoffFrequency (static_cast<float> (cutoffParam.getCurrentValue())); | |||
| filter.setResonance (static_cast<float> (qParam.getCurrentValue())); | |||
| @@ -630,7 +630,7 @@ private: | |||
| currentPositionLabel.setText (getPositionString (position, duration), sendNotification); | |||
| if (! positionSliderDragging) | |||
| positionSlider.setValue (duration != 0 ? (position / duration) : 0.0, dontSendNotification); | |||
| positionSlider.setValue (approximatelyEqual (duration, 0.0) ? 0.0 : (position / duration), dontSendNotification); | |||
| } | |||
| void seekVideoToStart() | |||
| @@ -97,8 +97,8 @@ public: | |||
| // start a tail-off by setting this flag. The render callback will pick up on | |||
| // this and do a fade out, calling clearCurrentNote() when it's finished. | |||
| if (tailOff == 0.0) // we only need to begin a tail-off if it's not already doing so - the | |||
| // stopNote method could be called more than once. | |||
| if (approximatelyEqual (tailOff, 0.0)) // we only need to begin a tail-off if it's not already doing so - the | |||
| // stopNote method could be called more than once. | |||
| tailOff = 1.0; | |||
| } | |||
| else | |||
| @@ -122,7 +122,7 @@ public: | |||
| void renderNextBlock (AudioBuffer<float>& outputBuffer, int startSample, int numSamples) override | |||
| { | |||
| if (angleDelta != 0.0) | |||
| if (! approximatelyEqual (angleDelta, 0.0)) | |||
| { | |||
| if (tailOff > 0.0) | |||
| { | |||
| @@ -969,7 +969,7 @@ private: | |||
| //============================================================================== | |||
| static String getPanningTextForValue (float value) | |||
| { | |||
| if (value == 0.5f) | |||
| if (approximatelyEqual (value, 0.5f)) | |||
| return "center"; | |||
| if (value < 0.5f) | |||
| @@ -291,7 +291,7 @@ public: | |||
| { | |||
| jassert (currentlyPlayingNote.keyState == MPENote::off); | |||
| if (allowTailOff && tailOff == 0.0) | |||
| if (allowTailOff && approximatelyEqual (tailOff, 0.0)) | |||
| tailOff = 1.0; | |||
| else | |||
| stopNote(); | |||
| @@ -422,7 +422,7 @@ private: | |||
| bool isTailingOff() const | |||
| { | |||
| return tailOff != 0.0; | |||
| return ! approximatelyEqual (tailOff, 0.0); | |||
| } | |||
| void stopNote() | |||
| @@ -262,8 +262,8 @@ private: | |||
| // start a tail-off by setting this flag. The render callback will pick up on | |||
| // this and do a fade out, calling clearCurrentNote() when it's finished. | |||
| if (tailOff == 0.0) // we only need to begin a tail-off if it's not already doing so - the | |||
| // stopNote method could be called more than once. | |||
| if (approximatelyEqual (tailOff, 0.0)) // we only need to begin a tail-off if it's not already doing so - the | |||
| // stopNote method could be called more than once. | |||
| tailOff = 1.0; | |||
| } | |||
| else | |||
| @@ -287,7 +287,7 @@ private: | |||
| void renderNextBlock (AudioBuffer<float>& outputBuffer, int startSample, int numSamples) override | |||
| { | |||
| if (angleDelta != 0.0) | |||
| if (! approximatelyEqual (angleDelta, 0.0)) | |||
| { | |||
| if (tailOff > 0) | |||
| { | |||
| @@ -34,7 +34,7 @@ elseif((CMAKE_CXX_COMPILER_ID STREQUAL "Clang") OR (CMAKE_CXX_COMPILER_ID STREQU | |||
| -Wsign-conversion -Wbool-conversion -Wextra-semi -Wunreachable-code | |||
| -Wcast-align -Wshift-sign-overflow -Wmissing-prototypes | |||
| -Wnullable-to-nonnull-conversion -Wno-ignored-qualifiers -Wswitch-enum | |||
| -Wpedantic -Wdeprecated | |||
| -Wpedantic -Wdeprecated -Wfloat-equal | |||
| $<$<OR:$<COMPILE_LANGUAGE:CXX>,$<COMPILE_LANGUAGE:OBJCXX>>: | |||
| -Wzero-as-null-pointer-constant -Wunused-private-field | |||
| -Woverloaded-virtual -Wreorder | |||
| @@ -47,7 +47,7 @@ elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") | |||
| -Wunused-parameter -Wsign-compare -Wsign-conversion -Wunreachable-code | |||
| -Wcast-align -Wno-implicit-fallthrough -Wno-maybe-uninitialized | |||
| -Wno-ignored-qualifiers -Wswitch-enum | |||
| -Wredundant-decls -Wno-strict-overflow -Wshadow | |||
| -Wredundant-decls -Wno-strict-overflow -Wshadow -Wfloat-equal | |||
| $<$<COMPILE_LANGUAGE:CXX>: | |||
| -Woverloaded-virtual -Wreorder -Wzero-as-null-pointer-constant>) | |||
| endif() | |||
| @@ -145,7 +145,7 @@ struct SliderHandler : public ComponentTypeHandler | |||
| if (needsSliderListener (component)) | |||
| r << memberVariableName << "->addListener (this);\n"; | |||
| if (s->getSkewFactor() != 1.0) | |||
| if (! approximatelyEqual (s->getSkewFactor(), 1.0)) | |||
| r << memberVariableName << "->setSkewFactor (" << s->getSkewFactor() << ");\n"; | |||
| r << '\n'; | |||
| @@ -77,7 +77,7 @@ public: | |||
| && gradPos1 == other.gradPos1 | |||
| && gradPos2 == other.gradPos2 | |||
| && imageResourceName == other.imageResourceName | |||
| && imageOpacity == other.imageOpacity | |||
| && approximatelyEqual (imageOpacity, other.imageOpacity) | |||
| && imageAnchor == other.imageAnchor; | |||
| } | |||
| @@ -320,7 +320,7 @@ public: | |||
| return gradCol1.isTransparent() && gradCol2.isTransparent(); | |||
| case imageBrush: | |||
| return imageOpacity == 0.0; | |||
| return approximatelyEqual (imageOpacity, 0.0); | |||
| default: | |||
| jassertfalse; | |||
| @@ -244,7 +244,7 @@ void PaintElementImage::setOpacity (double newOpacity, const bool undoable) | |||
| { | |||
| newOpacity = jlimit (0.0, 1.0, newOpacity); | |||
| if (opacity != newOpacity) | |||
| if (! approximatelyEqual (opacity, newOpacity)) | |||
| { | |||
| if (undoable) | |||
| { | |||
| @@ -95,7 +95,7 @@ public: | |||
| void setCornerSize (const double newSize, const bool undoable) | |||
| { | |||
| if (newSize != cornerSize) | |||
| if (! approximatelyEqual (newSize, cornerSize)) | |||
| { | |||
| if (undoable) | |||
| { | |||
| @@ -132,7 +132,7 @@ public: | |||
| s << getFontStyleCode (font) | |||
| << ")"; | |||
| if (font.getExtraKerningFactor() != 0.0f) | |||
| if (! approximatelyEqual (font.getExtraKerningFactor(), 0.0f)) | |||
| s << ".withExtraKerningFactor (" | |||
| << CodeHelpers::floatLiteral (font.getExtraKerningFactor(), 3) | |||
| << ")"; | |||
| @@ -184,7 +184,7 @@ void PaintRoutineEditor::refreshAllElements() | |||
| repaint(); | |||
| } | |||
| if (componentOverlayOpacity != document.getComponentOverlayOpacity()) | |||
| if (! approximatelyEqual (componentOverlayOpacity, document.getComponentOverlayOpacity())) | |||
| { | |||
| componentOverlay = Image(); | |||
| componentOverlayOpacity = document.getComponentOverlayOpacity(); | |||
| @@ -420,10 +420,12 @@ public: | |||
| /** Compares two objects. */ | |||
| bool operator== (const PositionedRectangle& other) const noexcept | |||
| { | |||
| return x == other.x && y == other.y | |||
| && w == other.w && h == other.h | |||
| && xMode == other.xMode && yMode == other.yMode | |||
| && wMode == other.wMode && hMode == other.hMode; | |||
| const auto tie = [] (const PositionedRectangle& r) | |||
| { | |||
| return std::tie (r.x, r.y, r.xMode, r.yMode, r.wMode, r.hMode); | |||
| }; | |||
| return tie (*this) == tie (other); | |||
| } | |||
| /** Compares two objects. */ | |||
| @@ -245,7 +245,7 @@ void JucerDocument::setSnappingGrid (const int numPixels, const bool active, con | |||
| void JucerDocument::setComponentOverlayOpacity (const float alpha) | |||
| { | |||
| if (alpha != componentOverlayOpacity) | |||
| if (! approximatelyEqual (alpha, componentOverlayOpacity)) | |||
| { | |||
| componentOverlayOpacity = alpha; | |||
| changed(); | |||
| @@ -136,7 +136,7 @@ private: | |||
| for (auto w : widths) | |||
| total += w; | |||
| if (total == 1.0f) | |||
| if (approximatelyEqual (total, 1.0f)) | |||
| return; | |||
| auto diff = 1.0f - total; | |||
| @@ -320,10 +320,25 @@ public: | |||
| static CompilerWarningFlags getRecommendedForGCCAndLLVM() | |||
| { | |||
| CompilerWarningFlags result; | |||
| result.common = { "-Wall", "-Wstrict-aliasing", "-Wuninitialized", "-Wunused-parameter", | |||
| "-Wswitch-enum", "-Wsign-conversion", "-Wsign-compare", | |||
| "-Wunreachable-code", "-Wcast-align", "-Wno-ignored-qualifiers" }; | |||
| result.cpp = { "-Woverloaded-virtual", "-Wreorder", "-Wzero-as-null-pointer-constant" }; | |||
| result.common = { | |||
| "-Wall", | |||
| "-Wcast-align", | |||
| "-Wfloat-equal", | |||
| "-Wno-ignored-qualifiers", | |||
| "-Wsign-compare", | |||
| "-Wsign-conversion", | |||
| "-Wstrict-aliasing", | |||
| "-Wswitch-enum", | |||
| "-Wuninitialized", | |||
| "-Wunreachable-code", | |||
| "-Wunused-parameter" | |||
| }; | |||
| result.cpp = { | |||
| "-Woverloaded-virtual", | |||
| "-Wreorder", | |||
| "-Wzero-as-null-pointer-constant" | |||
| }; | |||
| return result; | |||
| } | |||
| @@ -599,7 +599,7 @@ public: | |||
| for (int ch = 0; ch < numChannels; ++ch) | |||
| for (int i = 0; i < numSamples; ++i) | |||
| expect (destBuffer.getSample (0, ch + (i * numChannels)) == sourceBuffer.getSample (ch, i)); | |||
| expectEquals (destBuffer.getSample (0, ch + (i * numChannels)), sourceBuffer.getSample (ch, i)); | |||
| } | |||
| beginTest ("Deinterleaving"); | |||
| @@ -620,7 +620,7 @@ public: | |||
| for (int ch = 0; ch < numChannels; ++ch) | |||
| for (int i = 0; i < numSamples; ++i) | |||
| expect (sourceBuffer.getSample (0, ch + (i * numChannels)) == destBuffer.getSample (ch, i)); | |||
| expectEquals (sourceBuffer.getSample (0, ch + (i * numChannels)), destBuffer.getSample (ch, i)); | |||
| } | |||
| } | |||
| }; | |||
| @@ -60,7 +60,7 @@ void AudioProcessLoadMeasurer::registerRenderTime (double milliseconds, int numS | |||
| void AudioProcessLoadMeasurer::registerRenderTimeLocked (double milliseconds, int numSamples) | |||
| { | |||
| if (msPerSample == 0) | |||
| if (approximatelyEqual (msPerSample, 0.0)) | |||
| return; | |||
| const auto maxMilliseconds = numSamples * msPerSample; | |||
| @@ -686,11 +686,11 @@ public: | |||
| jassert (isPositiveAndBelow (channel, numChannels)); | |||
| jassert (startSample >= 0 && numSamples >= 0 && startSample + numSamples <= size); | |||
| if (gain != Type (1) && ! isClear) | |||
| if (! approximatelyEqual (gain, Type (1)) && ! isClear) | |||
| { | |||
| auto* d = channels[channel] + startSample; | |||
| if (gain == Type()) | |||
| if (approximatelyEqual (gain, Type())) | |||
| FloatVectorOperations::clear (d, numSamples); | |||
| else | |||
| FloatVectorOperations::multiply (d, gain, numSamples); | |||
| @@ -728,7 +728,7 @@ public: | |||
| { | |||
| if (! isClear) | |||
| { | |||
| if (startGain == endGain) | |||
| if (approximatelyEqual (startGain, endGain)) | |||
| { | |||
| applyGain (channel, startSample, numSamples, startGain); | |||
| } | |||
| @@ -798,7 +798,7 @@ public: | |||
| jassert (isPositiveAndBelow (sourceChannel, source.numChannels)); | |||
| jassert (sourceStartSample >= 0 && sourceStartSample + numSamples <= source.size); | |||
| if (gainToApplyToSource != 0 && numSamples > 0 && ! source.isClear) | |||
| if (! approximatelyEqual (gainToApplyToSource, (Type) 0) && numSamples > 0 && ! source.isClear) | |||
| { | |||
| auto* d = channels[destChannel] + destStartSample; | |||
| auto* s = source.channels[sourceChannel] + sourceStartSample; | |||
| @@ -809,14 +809,14 @@ public: | |||
| { | |||
| isClear = false; | |||
| if (gainToApplyToSource != Type (1)) | |||
| if (! approximatelyEqual (gainToApplyToSource, Type (1))) | |||
| FloatVectorOperations::copyWithMultiply (d, s, gainToApplyToSource, numSamples); | |||
| else | |||
| FloatVectorOperations::copy (d, s, numSamples); | |||
| } | |||
| else | |||
| { | |||
| if (gainToApplyToSource != Type (1)) | |||
| if (! approximatelyEqual (gainToApplyToSource, Type (1))) | |||
| FloatVectorOperations::addWithMultiply (d, s, gainToApplyToSource, numSamples); | |||
| else | |||
| FloatVectorOperations::add (d, s, numSamples); | |||
| @@ -1676,7 +1676,7 @@ public: | |||
| static bool areAllValuesEqual (const ValueType* d, int num, ValueType target) | |||
| { | |||
| while (--num >= 0) | |||
| if (*d++ != target) | |||
| if (! exactlyEqual (*d++, target)) | |||
| return false; | |||
| return true; | |||
| @@ -160,7 +160,7 @@ namespace MidiFileHelpers | |||
| for (int i = 0; i < numEvents; ++i) | |||
| { | |||
| auto& m = tempoEvents.getEventPointer(i)->message; | |||
| auto& m = tempoEvents.getEventPointer (i)->message; | |||
| auto eventTime = m.getTimeStamp(); | |||
| if (eventTime >= time) | |||
| @@ -174,9 +174,9 @@ namespace MidiFileHelpers | |||
| while (i + 1 < numEvents) | |||
| { | |||
| auto& m2 = tempoEvents.getEventPointer(i + 1)->message; | |||
| auto& m2 = tempoEvents.getEventPointer (i + 1)->message; | |||
| if (m2.getTimeStamp() != eventTime) | |||
| if (! approximatelyEqual (m2.getTimeStamp(), eventTime)) | |||
| break; | |||
| if (m2.isTempoMetaEvent()) | |||
| @@ -266,7 +266,7 @@ void MidiMessageSequence::updateMatchedPairs() noexcept | |||
| void MidiMessageSequence::addTimeToMessages (double delta) noexcept | |||
| { | |||
| if (delta != 0) | |||
| if (! approximatelyEqual (delta, 0.0)) | |||
| for (auto* m : list) | |||
| m->message.addToTimeStamp (delta); | |||
| } | |||
| @@ -554,7 +554,7 @@ struct MidiMessageSequenceTest : public UnitTest | |||
| { | |||
| const auto isEqual = [this] (const ControlValue& cv, const MidiMessage& msg) | |||
| { | |||
| return msg.getTimeStamp() == time | |||
| return exactlyEqual (msg.getTimeStamp(), time) | |||
| && msg.isController() | |||
| && msg.getChannel() == channel | |||
| && msg.getControllerNumber() == cv.control | |||
| @@ -107,7 +107,7 @@ void MPESynthesiserBase::renderNextBlock (AudioBuffer<floatType>& outputAudio, | |||
| int numSamples) | |||
| { | |||
| // you must set the sample rate before using this! | |||
| jassert (sampleRate != 0); | |||
| jassert (! approximatelyEqual (sampleRate, 0.0)); | |||
| const ScopedLock sl (noteStateLock); | |||
| @@ -144,7 +144,7 @@ template void MPESynthesiserBase::renderNextBlock<double> (AudioBuffer<double>&, | |||
| //============================================================================== | |||
| void MPESynthesiserBase::setCurrentPlaybackSampleRate (const double newRate) | |||
| { | |||
| if (sampleRate != newRate) | |||
| if (! approximatelyEqual (sampleRate, newRate)) | |||
| { | |||
| const ScopedLock sl (noteStateLock); | |||
| instrument.releaseAllNotes(); | |||
| @@ -263,13 +263,13 @@ public: | |||
| } | |||
| } | |||
| auto numChannels = tag & 0xffff; | |||
| const auto numChannels = tag & 0xffff; | |||
| if (tag >= coreAudioHOASN3DLayoutTag && tag <= (coreAudioHOASN3DLayoutTag | 0xffff)) | |||
| { | |||
| auto sqrtMinusOne = std::sqrt (static_cast<float> (numChannels)) - 1.0f; | |||
| auto ambisonicOrder = jmax (0, static_cast<int> (std::floor (sqrtMinusOne))); | |||
| const auto ambisonicOrder = AudioChannelSet::getAmbisonicOrderForNumChannels (static_cast<int> (numChannels)); | |||
| if (static_cast<float> (ambisonicOrder) == sqrtMinusOne) | |||
| if (ambisonicOrder != -1) | |||
| return AudioChannelSet::ambisonic (ambisonicOrder).getChannelTypes(); | |||
| } | |||
| @@ -51,7 +51,7 @@ void BufferingAudioSource::prepareToPlay (int samplesPerBlockExpected, double ne | |||
| { | |||
| auto bufferSizeNeeded = jmax (samplesPerBlockExpected * 2, numberOfSamplesToBuffer); | |||
| if (newSampleRate != sampleRate | |||
| if (! approximatelyEqual (newSampleRate, sampleRate) | |||
| || bufferSizeNeeded != buffer.getNumSamples() | |||
| || ! isPrepared) | |||
| { | |||
| @@ -184,7 +184,7 @@ struct MemoryAudioSourceTests : public UnitTest | |||
| play (source, channelInfo); | |||
| for (int sample = 0; sample < buffer.getNumSamples(); ++sample) | |||
| expect (bufferToFill.getSample (0, sample + buffer.getNumSamples()) == buffer.getSample (0, sample)); | |||
| expectEquals (bufferToFill.getSample (0, sample + buffer.getNumSamples()), buffer.getSample (0, sample)); | |||
| expect (! isSilent (bufferToFill)); | |||
| } | |||
| @@ -219,7 +219,7 @@ struct MemoryAudioSourceTests : public UnitTest | |||
| for (int i = 0; i < 100; ++i) | |||
| { | |||
| play (source, channelInfo); | |||
| expect (bufferToFill.getSample (0, 0) == buffer.getSample (0, (i * blockSize) % buffer.getNumSamples())); | |||
| expectEquals (bufferToFill.getSample (0, 0), buffer.getSample (0, (i * blockSize) % buffer.getNumSamples())); | |||
| } | |||
| } | |||
| } | |||
| @@ -88,7 +88,7 @@ void ResamplingAudioSource::getNextAudioBlock (const AudioSourceChannelInfo& inf | |||
| localRatio = ratio; | |||
| } | |||
| if (lastRatio != localRatio) | |||
| if (! approximatelyEqual (lastRatio, localRatio)) | |||
| { | |||
| createLowPass (localRatio); | |||
| lastRatio = localRatio; | |||
| @@ -62,7 +62,7 @@ void ToneGeneratorAudioSource::releaseResources() | |||
| void ToneGeneratorAudioSource::getNextAudioBlock (const AudioSourceChannelInfo& info) | |||
| { | |||
| if (phasePerSample == 0.0) | |||
| if (approximatelyEqual (phasePerSample, 0.0)) | |||
| phasePerSample = MathConstants<double>::twoPi / (sampleRate / frequency); | |||
| for (int i = 0; i < info.numSamples; ++i) | |||
| @@ -153,7 +153,7 @@ void Synthesiser::setMinimumRenderingSubdivisionSize (int numSamples, bool shoul | |||
| //============================================================================== | |||
| void Synthesiser::setCurrentPlaybackSampleRate (const double newRate) | |||
| { | |||
| if (sampleRate != newRate) | |||
| if (! approximatelyEqual (sampleRate, newRate)) | |||
| { | |||
| const ScopedLock sl (lock); | |||
| allNotesOff (0, false); | |||
| @@ -171,7 +171,7 @@ void Synthesiser::processNextBlock (AudioBuffer<floatType>& outputAudio, | |||
| int numSamples) | |||
| { | |||
| // must set the sample rate before using this! | |||
| jassert (sampleRate != 0); | |||
| jassert (! exactlyEqual (sampleRate, 0.0)); | |||
| const int targetChannels = outputAudio.getNumChannels(); | |||
| auto midiIterator = midiData.findNextSamplePosition (startSample); | |||
| @@ -73,7 +73,7 @@ private: | |||
| sign = (sincPosition < 0 ? -1 : 1); | |||
| } | |||
| if (sincPosition == 0.0f) | |||
| if (approximatelyEqual (sincPosition, 0.0f)) | |||
| result += inputs[samplePosition]; | |||
| else if (sincPosition < floatCrossings && sincPosition > -floatCrossings) | |||
| result += inputs[samplePosition] * windowedSinc (firstFrac, index); | |||
| @@ -237,7 +237,8 @@ public: | |||
| SmoothedValue (FloatType initialValue) noexcept | |||
| { | |||
| // Multiplicative smoothed values cannot ever reach 0! | |||
| jassert (! (std::is_same_v<SmoothingType, ValueSmoothingTypes::Multiplicative> && initialValue == 0)); | |||
| jassert (! (std::is_same_v<SmoothingType, ValueSmoothingTypes::Multiplicative> | |||
| && approximatelyEqual (initialValue, (FloatType) 0))); | |||
| // Visual Studio can't handle base class initialisation with CRTP | |||
| this->currentValue = initialValue; | |||
| @@ -270,7 +271,7 @@ public: | |||
| */ | |||
| void setTargetValue (FloatType newValue) noexcept | |||
| { | |||
| if (newValue == this->target) | |||
| if (approximatelyEqual (newValue, this->target)) | |||
| return; | |||
| if (stepsToTarget <= 0) | |||
| @@ -280,7 +281,8 @@ public: | |||
| } | |||
| // Multiplicative smoothed values cannot ever reach 0! | |||
| jassert (! (std::is_same_v<SmoothingType, ValueSmoothingTypes::Multiplicative> && newValue == 0)); | |||
| jassert (! (std::is_same_v<SmoothingType, ValueSmoothingTypes::Multiplicative> | |||
| && approximatelyEqual (newValue, (FloatType) 0))); | |||
| this->target = newValue; | |||
| this->countdown = stepsToTarget; | |||
| @@ -56,7 +56,7 @@ void MidiMessageCollector::addMessageToQueue (const MidiMessage& message) | |||
| // the messages that come in here need to be time-stamped correctly - see MidiInput | |||
| // for details of what the number should be. | |||
| jassert (message.getTimeStamp() != 0); | |||
| jassert (! approximatelyEqual (message.getTimeStamp(), 0.0)); | |||
| auto sampleNumber = (int) ((message.getTimeStamp() - 0.001 * lastCallbackTime) * sampleRate); | |||
| @@ -938,7 +938,7 @@ struct iOSAudioIODevice::Pimpl : public AsyncUpdater | |||
| { | |||
| if (! firstHostTime) | |||
| { | |||
| if ((time->mSampleTime - lastSampleTime) != lastNumFrames) | |||
| if (! approximatelyEqual ((time->mSampleTime - lastSampleTime), (double) lastNumFrames)) | |||
| xrun++; | |||
| } | |||
| else | |||
| @@ -1159,7 +1159,7 @@ struct iOSAudioIODevice::Pimpl : public AsyncUpdater | |||
| &desc, | |||
| &dataSize); | |||
| if (desc.mSampleRate != 0 && desc.mSampleRate != sampleRate) | |||
| if (! approximatelyEqual (desc.mSampleRate, 0.0) && ! approximatelyEqual (desc.mSampleRate, sampleRate)) | |||
| { | |||
| JUCE_IOS_AUDIO_LOG ("Stream format has changed: Sample rate " << desc.mSampleRate); | |||
| triggerAsyncUpdate(); | |||
| @@ -966,7 +966,7 @@ public: | |||
| jassert (timestamp == nullptr || (((timestamp->mFlags & kAudioTimeStampSampleTimeValid) != 0) | |||
| && ((timestamp->mFlags & kAudioTimeStampHostTimeValid) != 0))); | |||
| if (previousSampleTime == invalidSampleTime) | |||
| if (exactlyEqual (previousSampleTime, invalidSampleTime)) | |||
| previousSampleTime = timestamp != nullptr ? timestamp->mSampleTime : 0.0; | |||
| if (timestamp != nullptr && std::fabs (previousSampleTime - timestamp->mSampleTime) >= 1.0) | |||
| @@ -1091,7 +1091,7 @@ private: | |||
| if (! updateDetailsFromDevice()) | |||
| owner.stopInternal(); | |||
| else if ((oldBufferSize != bufferSize || oldSampleRate != sampleRate) && owner.shouldRestartDevice()) | |||
| else if ((oldBufferSize != bufferSize || ! approximatelyEqual (oldSampleRate, sampleRate)) && owner.shouldRestartDevice()) | |||
| owner.restart(); | |||
| } | |||
| @@ -1577,7 +1577,7 @@ public: | |||
| { | |||
| auto deviceSampleRate = d->getCurrentSampleRate(); | |||
| if (deviceSampleRate != sampleRateRequested) | |||
| if (! approximatelyEqual (deviceSampleRate, sampleRateRequested)) | |||
| { | |||
| if (! getAvailableSampleRates().contains (deviceSampleRate)) | |||
| return; | |||
| @@ -1912,7 +1912,7 @@ private: | |||
| for (auto& d : getDeviceWrappers()) | |||
| { | |||
| if (d->getCurrentSampleRate() != currentSampleRate) | |||
| if (! approximatelyEqual (d->getCurrentSampleRate(), currentSampleRate)) | |||
| { | |||
| d->setCurrentSampleRate (currentSampleRate); | |||
| anySampleRateChanges = true; | |||
| @@ -111,15 +111,16 @@ namespace FlacNamespace | |||
| #endif | |||
| JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wconversion", | |||
| "-Wshadow", | |||
| "-Wdeprecated-register", | |||
| "-Wswitch-enum", | |||
| "-Wswitch-default", | |||
| "-Wfloat-equal", | |||
| "-Wimplicit-fallthrough", | |||
| "-Wzero-as-null-pointer-constant", | |||
| "-Wsign-conversion", | |||
| "-Wlanguage-extension-token", | |||
| "-Wredundant-decls", | |||
| "-Wlanguage-extension-token") | |||
| "-Wshadow", | |||
| "-Wsign-conversion", | |||
| "-Wswitch-default", | |||
| "-Wswitch-enum", | |||
| "-Wzero-as-null-pointer-constant") | |||
| #if JUCE_INTEL | |||
| #if JUCE_32BIT | |||
| @@ -37,20 +37,21 @@ namespace OggVorbisNamespace | |||
| #if JUCE_INCLUDE_OGGVORBIS_CODE || ! defined (JUCE_INCLUDE_OGGVORBIS_CODE) | |||
| JUCE_BEGIN_IGNORE_WARNINGS_MSVC (4267 4127 4244 4996 4100 4701 4702 4013 4133 4206 4305 4189 4706 4995 4365 4456 4457 4459 6297 6011 6001 6308 6255 6386 6385 6246 6387 6263 6262 28182) | |||
| JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wconversion", | |||
| "-Wshadow", | |||
| "-Wfloat-conversion", | |||
| "-Wdeprecated-register", | |||
| JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wcast-align", | |||
| "-Wconversion", | |||
| "-Wdeprecated-declarations", | |||
| "-Wswitch-enum", | |||
| "-Wzero-as-null-pointer-constant", | |||
| "-Wsign-conversion", | |||
| "-Wswitch-default", | |||
| "-Wredundant-decls", | |||
| "-Wdeprecated-register", | |||
| "-Wfloat-conversion", | |||
| "-Wfloat-equal", | |||
| "-Wmaybe-uninitialized", | |||
| "-Wmisleading-indentation", | |||
| "-Wmissing-prototypes", | |||
| "-Wcast-align", | |||
| "-Wmaybe-uninitialized") | |||
| "-Wredundant-decls", | |||
| "-Wshadow", | |||
| "-Wsign-conversion", | |||
| "-Wswitch-default", | |||
| "-Wswitch-enum", | |||
| "-Wzero-as-null-pointer-constant") | |||
| JUCE_BEGIN_NO_SANITIZE ("undefined") | |||
| #include "oggvorbis/vorbisenc.h" | |||
| @@ -50,7 +50,7 @@ struct VSTWindowUtilities | |||
| comp->addToDesktop (desktopFlags | defaultFlags, parentView); | |||
| // (this workaround is because Wavelab provides a zero-size parent view..) | |||
| if ([parentView frame].size.height == 0) | |||
| if (approximatelyEqual ([parentView frame].size.height, 0.0)) | |||
| [((NSView*) comp->getWindowHandle()) setFrameOrigin: NSZeroPoint]; | |||
| comp->setVisible (true); | |||
| @@ -35,16 +35,17 @@ | |||
| #include <juce_audio_processors/format_types/juce_LegacyAudioParameter.cpp> | |||
| JUCE_BEGIN_IGNORE_WARNINGS_MSVC (4127 4512 4996) | |||
| JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wnon-virtual-dtor", | |||
| "-Wsign-conversion", | |||
| JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wdeprecated-declarations", | |||
| "-Wextra-semi", | |||
| "-Wshift-sign-overflow", | |||
| "-Wpragma-pack", | |||
| "-Wzero-as-null-pointer-constant", | |||
| "-Winconsistent-missing-destructor-override", | |||
| "-Wfloat-equal", | |||
| "-Wfour-char-constants", | |||
| "-Winconsistent-missing-destructor-override", | |||
| "-Wnon-virtual-dtor", | |||
| "-Wpragma-pack", | |||
| "-Wshift-sign-overflow", | |||
| "-Wsign-conversion", | |||
| "-Wtautological-overlap-compare", | |||
| "-Wdeprecated-declarations") | |||
| "-Wzero-as-null-pointer-constant") | |||
| #include <AAX_Version.h> | |||
| @@ -1004,7 +1005,7 @@ namespace AAXClasses | |||
| { | |||
| auto newValue = static_cast<float> (value); | |||
| if (newValue != param->getValue()) | |||
| if (! approximatelyEqual (newValue, param->getValue())) | |||
| { | |||
| param->setValue (newValue); | |||
| @@ -40,12 +40,13 @@ JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wzero-as-null-pointer-constant") | |||
| #include <Libs/AAXLibrary/source/AAX_CAutoreleasePool.Win.cpp> | |||
| JUCE_END_IGNORE_WARNINGS_GCC_LIKE | |||
| JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wunused-parameter", | |||
| "-Wshift-sign-overflow", | |||
| JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wdeprecated-declarations", | |||
| "-Wextra-semi", | |||
| "-Wzero-as-null-pointer-constant", | |||
| "-Wfloat-equal", | |||
| "-Winconsistent-missing-destructor-override", | |||
| "-Wdeprecated-declarations") | |||
| "-Wshift-sign-overflow", | |||
| "-Wunused-parameter", | |||
| "-Wzero-as-null-pointer-constant") | |||
| JUCE_BEGIN_IGNORE_WARNINGS_MSVC (6001 6053 4996 5033 4068 4996) | |||
| #include <Libs/AAXLibrary/source/AAX_CChunkDataParser.cpp> | |||
| @@ -29,21 +29,22 @@ | |||
| #if JucePlugin_Build_AU | |||
| JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wshorten-64-to-32", | |||
| "-Wunused-parameter", | |||
| "-Wdeprecated-declarations", | |||
| "-Wsign-conversion", | |||
| JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wcast-align", | |||
| "-Wconversion", | |||
| "-Woverloaded-virtual", | |||
| "-Wdeprecated-anon-enum-enum-conversion", | |||
| "-Wdeprecated-declarations", | |||
| "-Wextra-semi", | |||
| "-Wcast-align", | |||
| "-Wfloat-equal", | |||
| "-Wformat-pedantic", | |||
| "-Wgnu-zero-variadic-macro-arguments", | |||
| "-Wnullable-to-nonnull-conversion", | |||
| "-Woverloaded-virtual", | |||
| "-Wshadow", | |||
| "-Wshorten-64-to-32", | |||
| "-Wsign-conversion", | |||
| "-Wswitch-enum", | |||
| "-Wzero-as-null-pointer-constant", | |||
| "-Wnullable-to-nonnull-conversion", | |||
| "-Wgnu-zero-variadic-macro-arguments", | |||
| "-Wformat-pedantic", | |||
| "-Wdeprecated-anon-enum-enum-conversion") | |||
| "-Wunused-parameter", | |||
| "-Wzero-as-null-pointer-constant") | |||
| #include <juce_audio_plugin_client/detail/juce_IncludeSystemHeaders.h> | |||
| @@ -1066,7 +1067,7 @@ public: | |||
| { | |||
| auto value = inValue / getMaximumParameterValue (param); | |||
| if (value != param->getValue()) | |||
| if (! approximatelyEqual (value, param->getValue())) | |||
| { | |||
| inParameterChangedCallback = true; | |||
| param->setValueNotifyingHost (value); | |||
| @@ -1634,7 +1635,7 @@ public: | |||
| static NSTimeInterval lastEventTime = 0; // check we're not recursively sending the same event | |||
| NSTimeInterval eventTime = [[NSApp currentEvent] timestamp]; | |||
| if (lastEventTime != eventTime) | |||
| if (! approximatelyEqual (lastEventTime, eventTime)) | |||
| { | |||
| lastEventTime = eventTime; | |||
| @@ -29,28 +29,29 @@ | |||
| #include <juce_core/system/juce_CompilerWarnings.h> | |||
| JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wparentheses", | |||
| "-Wextra-tokens", | |||
| JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wambiguous-reversed-operator", | |||
| "-Wc99-extensions", | |||
| "-Wcast-align", | |||
| "-Wcomment", | |||
| "-Wconversion", | |||
| "-Wunused-parameter", | |||
| "-Wunused", | |||
| "-Wdeprecated-anon-enum-enum-conversion", | |||
| "-Wextra-semi", | |||
| "-Wextra-tokens", | |||
| "-Wfloat-equal", | |||
| "-Wformat-pedantic", | |||
| "-Wfour-char-constants", | |||
| "-Wgnu-zero-variadic-macro-arguments", | |||
| "-Wshadow-all", | |||
| "-Wcast-align", | |||
| "-Wswitch-enum", | |||
| "-Wimplicit-fallthrough", | |||
| "-Wzero-as-null-pointer-constant", | |||
| "-Wnullable-to-nonnull-conversion", | |||
| "-Wignored-qualifiers", | |||
| "-Wfour-char-constants", | |||
| "-Wimplicit-fallthrough", | |||
| "-Wmissing-prototypes", | |||
| "-Wdeprecated-anon-enum-enum-conversion", | |||
| "-Wambiguous-reversed-operator", | |||
| "-Wnullable-to-nonnull-conversion", | |||
| "-Wparentheses", | |||
| "-Wshadow-all", | |||
| "-Wswitch-enum", | |||
| "-Wunknown-attributes", | |||
| "-Wc99-extensions") | |||
| "-Wunused", | |||
| "-Wunused-parameter", | |||
| "-Wzero-as-null-pointer-constant") | |||
| // From MacOS 10.13 and iOS 11 Apple has (sensibly!) stopped defining a whole | |||
| // set of functions with rather generic names. However, we still need a couple | |||
| @@ -1350,7 +1350,7 @@ private: | |||
| void setAudioProcessorParameter (AudioProcessorParameter* juceParam, float value) | |||
| { | |||
| if (value != juceParam->getValue()) | |||
| if (! approximatelyEqual (value, juceParam->getValue())) | |||
| { | |||
| juceParam->setValue (value); | |||
| @@ -1458,7 +1458,7 @@ private: | |||
| const auto numProcessorBusesOut = AudioUnitHelpers::getBusCount (processor, false); | |||
| if (lastTimeStamp.mSampleTime != timestamp->mSampleTime) | |||
| if (! approximatelyEqual (lastTimeStamp.mSampleTime, timestamp->mSampleTime)) | |||
| { | |||
| // process params and incoming midi (only once for a given timestamp) | |||
| midiMessages.clear(); | |||
| @@ -156,7 +156,7 @@ public: | |||
| return value; | |||
| }(); | |||
| if (scaledValue != param->getValue()) | |||
| if (! approximatelyEqual (scaledValue, param->getValue())) | |||
| { | |||
| ScopedValueSetter<bool> scope (ignoreCallbacks, true); | |||
| param->setValueNotifyingHost (scaledValue); | |||
| @@ -326,7 +326,7 @@ public: | |||
| info->setBpm (parser.parseNumericAtom<float> (atomBeatsPerMinute)); | |||
| info->setPpqPosition (parser.parseNumericAtom<double> (atomBeat)); | |||
| info->setIsPlaying (parser.parseNumericAtom<float> (atomSpeed).orFallback (0.0f) != 0.0f); | |||
| info->setIsPlaying (! approximatelyEqual (parser.parseNumericAtom<float> (atomSpeed).orFallback (0.0f), 0.0f)); | |||
| info->setBarCount (parser.parseNumericAtom<int64_t> (atomBar)); | |||
| if (const auto parsed = parser.parseNumericAtom<int64_t> (atomFrame)) | |||
| @@ -552,7 +552,7 @@ public: | |||
| if (detail::PluginUtilities::getHostType().isAbletonLive() | |||
| && hostCallback != nullptr | |||
| && processor->getTailLengthSeconds() == std::numeric_limits<double>::infinity()) | |||
| && std::isinf (processor->getTailLengthSeconds())) | |||
| { | |||
| AbletonLiveHostSpecific hostCmd; | |||
| @@ -645,7 +645,7 @@ public: | |||
| }()); | |||
| const auto effectiveRate = info.getFrameRate().hasValue() ? info.getFrameRate()->getEffectiveRate() : 0.0; | |||
| info.setEditOriginTime (effectiveRate != 0.0 ? makeOptional (ti->smpteOffset / (80.0 * effectiveRate)) : nullopt); | |||
| info.setEditOriginTime (! approximatelyEqual (effectiveRate, 0.0) ? makeOptional (ti->smpteOffset / (80.0 * effectiveRate)) : nullopt); | |||
| } | |||
| info.setIsRecording ((ti->flags & Vst2::kVstTransportRecording) != 0); | |||
| @@ -1395,7 +1395,7 @@ private: | |||
| void setValueAndNotifyIfChanged (AudioProcessorParameter& param, float newValue) | |||
| { | |||
| if (param.getValue() == newValue) | |||
| if (approximatelyEqual (param.getValue(), newValue)) | |||
| return; | |||
| inParameterChangedCallback = true; | |||
| @@ -1896,7 +1896,7 @@ private: | |||
| auto tailSeconds = processor->getTailLengthSeconds(); | |||
| if (tailSeconds == std::numeric_limits<double>::infinity()) | |||
| if (std::isinf (tailSeconds)) | |||
| result = std::numeric_limits<int32>::max(); | |||
| else | |||
| result = static_cast<int32> (tailSeconds * sampleRate); | |||
| @@ -701,7 +701,7 @@ static thread_local bool inParameterChangedCallback = false; | |||
| static void setValueAndNotifyIfChanged (AudioProcessorParameter& param, float newValue) | |||
| { | |||
| if (param.getValue() == newValue) | |||
| if (approximatelyEqual (param.getValue(), newValue)) | |||
| return; | |||
| const InParameterChangedCallbackSetter scopedSetter { inParameterChangedCallback }; | |||
| @@ -830,7 +830,7 @@ public: | |||
| { | |||
| v = jlimit (0.0, 1.0, v); | |||
| if (v != valueNormalized) | |||
| if (! approximatelyEqual (v, valueNormalized)) | |||
| { | |||
| valueNormalized = v; | |||
| @@ -910,7 +910,7 @@ public: | |||
| if (programValue != owner.getCurrentProgram()) | |||
| owner.setCurrentProgram (programValue); | |||
| if (valueNormalized != v) | |||
| if (! approximatelyEqual (valueNormalized, v)) | |||
| { | |||
| valueNormalized = v; | |||
| changed(); | |||
| @@ -1931,7 +1931,7 @@ private: | |||
| auto aspectRatio = (float) constrainer->getFixedAspectRatio(); | |||
| if (aspectRatio != 0.0) | |||
| if (! approximatelyEqual (aspectRatio, 0.0f)) | |||
| { | |||
| bool adjustWidth = (width / height > aspectRatio); | |||
| @@ -1939,9 +1939,9 @@ private: | |||
| { | |||
| auto currentEditorBounds = editor->getBounds().toFloat(); | |||
| if (currentEditorBounds.getWidth() == width && currentEditorBounds.getHeight() != height) | |||
| if (approximatelyEqual (currentEditorBounds.getWidth(), width) && ! approximatelyEqual (currentEditorBounds.getHeight(), height)) | |||
| adjustWidth = true; | |||
| else if (currentEditorBounds.getHeight() == height && currentEditorBounds.getWidth() != width) | |||
| else if (approximatelyEqual (currentEditorBounds.getHeight(), height) && ! approximatelyEqual (currentEditorBounds.getWidth(), width)) | |||
| adjustWidth = false; | |||
| } | |||
| @@ -2322,7 +2322,7 @@ private: | |||
| { | |||
| const auto previous = std::exchange (scaleFactor, newFactor).get(); | |||
| if (previous == scaleFactor.get()) | |||
| if (approximatelyEqual (previous, scaleFactor.get())) | |||
| return; | |||
| if (owner != nullptr) | |||
| @@ -3422,7 +3422,7 @@ public: | |||
| if (tailLengthSeconds <= 0.0 || processSetup.sampleRate <= 0.0) | |||
| return Vst::kNoTail; | |||
| if (tailLengthSeconds == std::numeric_limits<double>::infinity()) | |||
| if (std::isinf (tailLengthSeconds)) | |||
| return Vst::kInfiniteTail; | |||
| return (Steinberg::uint32) roundToIntAccurate (tailLengthSeconds * processSetup.sampleRate); | |||
| @@ -1247,7 +1247,7 @@ public: | |||
| AudioUnitGetProperty (audioUnit, kAudioUnitProperty_SampleRate, scope, static_cast<UInt32> (i), &sampleRate, &sampleRateSize); | |||
| if (sampleRate != sr) | |||
| if (! approximatelyEqual (sampleRate, sr)) | |||
| { | |||
| if (isAUv3) // setting kAudioUnitProperty_SampleRate fails on AUv3s | |||
| { | |||
| @@ -2739,7 +2739,7 @@ private: | |||
| if (@available (macOS 10.11, *)) | |||
| size = [controller preferredContentSize]; | |||
| if (size.width == 0 || size.height == 0) | |||
| if (approximatelyEqual (size.width, 0.0) || approximatelyEqual (size.height, 0.0)) | |||
| size = controller.view.frame.size; | |||
| return CGSizeMake (jmax ((CGFloat) 20.0f, size.width), | |||
| @@ -457,7 +457,7 @@ private: | |||
| { | |||
| const ScopedLock sl (pluginInstance.lock); | |||
| if (paramValue.unscaled != newValue) | |||
| if (! approximatelyEqual (paramValue.unscaled, newValue)) | |||
| paramValue = ParameterValue (getNewParamScaled (interface->PortRangeHints [paramID], newValue), newValue); | |||
| } | |||
| } | |||
| @@ -3287,7 +3287,7 @@ private: | |||
| { | |||
| if (auto* r = ref.getComponent()) | |||
| { | |||
| if (std::exchange (r->nativeScaleFactor, platformScale) == platformScale) | |||
| if (approximatelyEqual (std::exchange (r->nativeScaleFactor, platformScale), platformScale)) | |||
| return; | |||
| r->nativeScaleFactor = platformScale; | |||
| @@ -31,6 +31,8 @@ JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wc99-extensions", | |||
| "-Wdeprecated-declarations", | |||
| "-Wextra-semi", | |||
| "-Wfloat-conversion", | |||
| "-Wfloat-equal", | |||
| "-Wformat-overflow", | |||
| "-Wimplicit-float-conversion", | |||
| "-Wimplicit-int-conversion", | |||
| "-Wmicrosoft-include", | |||
| @@ -44,8 +46,7 @@ JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wc99-extensions", | |||
| "-Wsign-conversion", | |||
| "-Wswitch-enum", | |||
| "-Wunused-parameter", | |||
| "-Wzero-as-null-pointer-constant", | |||
| "-Wformat-overflow") | |||
| "-Wzero-as-null-pointer-constant") | |||
| JUCE_BEGIN_IGNORE_WARNINGS_MSVC (4100 4200 4244 4267 4389 4702 4706 4800 4996 6308 28182 28183 6385 6386 6387 6011 6282 6323 6330 6001 6031) | |||
| extern "C" | |||
| @@ -32,44 +32,45 @@ | |||
| // Wow, those Steinberg guys really don't worry too much about compiler warnings. | |||
| JUCE_BEGIN_IGNORE_WARNINGS_LEVEL_MSVC (0, 4505 4702 6011 6031 6221 6386 6387 6330 6001 28199) | |||
| JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wdeprecated-copy-dtor", | |||
| "-Wnon-virtual-dtor", | |||
| "-Wdeprecated", | |||
| "-Wreorder", | |||
| "-Wunsequenced", | |||
| "-Wint-to-pointer-cast", | |||
| "-Wunused-parameter", | |||
| JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-W#warnings", | |||
| "-Wcast-align", | |||
| "-Wclass-memaccess", | |||
| "-Wcomma", | |||
| "-Wconversion", | |||
| "-Woverloaded-virtual", | |||
| "-Wshadow", | |||
| "-Wdeprecated-register", | |||
| "-Wunused-function", | |||
| "-Wsign-conversion", | |||
| "-Wsign-compare", | |||
| "-Wcpp", | |||
| "-Wdelete-non-virtual-dtor", | |||
| "-Wdeprecated", | |||
| "-Wdeprecated-copy-dtor", | |||
| "-Wdeprecated-declarations", | |||
| "-Wdeprecated-register", | |||
| "-Wextra", | |||
| "-Wextra-semi", | |||
| "-Wmissing-braces", | |||
| "-Wswitch-default", | |||
| "-Wshadow-field", | |||
| "-Wpragma-pack", | |||
| "-Wcomma", | |||
| "-Wzero-as-null-pointer-constant", | |||
| "-Winconsistent-missing-destructor-override", | |||
| "-Wcast-align", | |||
| "-Wfloat-equal", | |||
| "-Wformat", | |||
| "-Wformat=", | |||
| "-Wignored-qualifiers", | |||
| "-Winconsistent-missing-destructor-override", | |||
| "-Wint-to-pointer-cast", | |||
| "-Wmaybe-uninitialized", | |||
| "-Wmissing-braces", | |||
| "-Wmissing-field-initializers", | |||
| "-Wformat=", | |||
| "-Wformat", | |||
| "-Wpedantic", | |||
| "-Wextra", | |||
| "-Wclass-memaccess", | |||
| "-Wmissing-prototypes", | |||
| "-Wnon-virtual-dtor", | |||
| "-Woverloaded-virtual", | |||
| "-Wpedantic", | |||
| "-Wpragma-pack", | |||
| "-Wreorder", | |||
| "-Wshadow", | |||
| "-Wshadow-field", | |||
| "-Wsign-compare", | |||
| "-Wsign-conversion", | |||
| "-Wswitch-default", | |||
| "-Wtype-limits", | |||
| "-Wcpp", | |||
| "-W#warnings", | |||
| "-Wmaybe-uninitialized", | |||
| "-Wunused-but-set-variable") | |||
| "-Wunsequenced", | |||
| "-Wunused-but-set-variable", | |||
| "-Wunused-function", | |||
| "-Wunused-parameter", | |||
| "-Wzero-as-null-pointer-constant") | |||
| #undef DEVELOPMENT | |||
| #define DEVELOPMENT 0 // This avoids a Clang warning in Steinberg code about unused values | |||
| @@ -2498,7 +2498,7 @@ public: | |||
| // Avoid redundantly calling things like setActive, which can be a heavy-duty call for some plugins: | |||
| if (isActive | |||
| && getSampleRate() == newSampleRate | |||
| && approximatelyEqual (getSampleRate(), newSampleRate) | |||
| && getBlockSize() == estimatedSamplesPerBlock) | |||
| return; | |||
| @@ -3432,7 +3432,7 @@ private: | |||
| // call was processBlockBypassed, otherwise do nothing | |||
| if (processBlockBypassedCalled) | |||
| { | |||
| if (bypassParam != nullptr && (bypassParam->getValue() == 0.0f || ! lastProcessBlockCallWasBypass)) | |||
| if (bypassParam != nullptr && (approximatelyEqual (bypassParam->getValue(), 0.0f) || ! lastProcessBlockCallWasBypass)) | |||
| bypassParam->setValue (1.0f); | |||
| } | |||
| else | |||
| @@ -3618,7 +3618,7 @@ tresult VST3HostContext::performEdit (Vst::ParamID paramID, Vst::ParamValue valu | |||
| param->setValueNotifyingHost ((float) valueNormalised); | |||
| // did the plug-in already update the parameter internally | |||
| if (plugin->editController->getParamNormalized (paramID) != (float) valueNormalised) | |||
| if (! approximatelyEqual (plugin->editController->getParamNormalized (paramID), valueNormalised)) | |||
| return plugin->editController->setParamNormalized (paramID, valueNormalised); | |||
| return kResultTrue; | |||
| @@ -584,7 +584,7 @@ private: | |||
| bool allMatch (int channel, float value) const | |||
| { | |||
| const auto& buf = buffers[(size_t) channel]; | |||
| return std::all_of (buf.begin(), buf.end(), [&] (auto x) { return x == value; }); | |||
| return std::all_of (buf.begin(), buf.end(), [&] (auto x) { return exactlyEqual (x, value); }); | |||
| } | |||
| bool isClear (int channel) const | |||
| @@ -607,13 +607,13 @@ private: | |||
| static bool channelStartsWithValue (Steinberg::Vst::AudioBusBuffers& bus, size_t index, float value) | |||
| { | |||
| return bus.channelBuffers32[index][0] == value; | |||
| return exactlyEqual (bus.channelBuffers32[index][0], value); | |||
| } | |||
| static bool allMatch (const AudioBuffer<float>& buf, int index, float value) | |||
| { | |||
| const auto* ptr = buf.getReadPointer (index); | |||
| return std::all_of (ptr, ptr + buf.getNumSamples(), [&] (auto x) { return x == value; }); | |||
| return std::all_of (ptr, ptr + buf.getNumSamples(), [&] (auto x) { return exactlyEqual (x, value); }); | |||
| } | |||
| struct MultiBusBuffers | |||
| @@ -904,7 +904,7 @@ struct VSTPluginInstance final : public AudioPluginInstance, | |||
| { | |||
| const ScopedLock sl (pluginInstance.lock); | |||
| if (effect->getParameter (effect, getParameterIndex()) != newValue) | |||
| if (! approximatelyEqual (effect->getParameter (effect, getParameterIndex()), newValue)) | |||
| effect->setParameter (effect, getParameterIndex(), newValue); | |||
| } | |||
| } | |||
| @@ -2004,7 +2004,7 @@ private: | |||
| void setValue (float newValue) override | |||
| { | |||
| currentValue = (newValue != 0.0f); | |||
| currentValue = (! approximatelyEqual (newValue, 0.0f)); | |||
| if (parent.vstSupportsBypass) | |||
| parent.dispatch (Vst2::effSetBypass, 0, currentValue ? 1 : 0, nullptr, 0.0f); | |||
| @@ -2028,7 +2028,7 @@ private: | |||
| float getValue() const override { return currentValue; } | |||
| float getDefaultValue() const override { return 0.0f; } | |||
| String getName (int /*maximumStringLength*/) const override { return "Bypass"; } | |||
| String getText (float value, int) const override { return (value != 0.0f ? TRANS("On") : TRANS("Off")); } | |||
| String getText (float value, int) const override { return (! approximatelyEqual (value, 0.0f) ? TRANS("On") : TRANS("Off")); } | |||
| bool isAutomatable() const override { return true; } | |||
| bool isDiscrete() const override { return true; } | |||
| bool isBoolean() const override { return true; } | |||
| @@ -2740,7 +2740,7 @@ private: | |||
| { | |||
| if (processBlockBypassedCalled) | |||
| { | |||
| if (bypassParam->getValue() == 0.0f || ! lastProcessBlockCallWasBypass) | |||
| if (approximatelyEqual (bypassParam->getValue(), 0.0f) || ! lastProcessBlockCallWasBypass) | |||
| bypassParam->setValue (1.0f); | |||
| } | |||
| else | |||
| @@ -127,7 +127,7 @@ public: | |||
| if (processor != nullptr) | |||
| { | |||
| if (auto* bypassParam = processor->getBypassParameter()) | |||
| return (bypassParam->getValue() != 0.0f); | |||
| return ! approximatelyEqual (bypassParam->getValue(), 0.0f); | |||
| } | |||
| return bypassed; | |||
| @@ -378,7 +378,7 @@ private: | |||
| { | |||
| auto newVal = (float) slider.getValue(); | |||
| if (getParameter().getValue() != newVal) | |||
| if (! approximatelyEqual (getParameter().getValue(), newVal)) | |||
| { | |||
| if (! isDragging) | |||
| getParameter().beginChangeGesture(); | |||
| @@ -44,7 +44,7 @@ AudioParameterFloat::AudioParameterFloat (const ParameterID& idToUse, | |||
| { | |||
| int numDecimalPlaces = 7; | |||
| if (range.interval != 0.0f) | |||
| if (! approximatelyEqual (range.interval, 0.0f)) | |||
| { | |||
| if (approximatelyEqual (std::abs (range.interval - std::floor (range.interval)), 0.0f)) | |||
| return 0; | |||
| @@ -95,7 +95,7 @@ void AudioParameterFloat::valueChanged (float) {} | |||
| AudioParameterFloat& AudioParameterFloat::operator= (float newValue) | |||
| { | |||
| if (value != newValue) | |||
| if (! approximatelyEqual ((float) value, newValue)) | |||
| setValueNotifyingHost (convertTo0to1 (newValue)); | |||
| return *this; | |||
| @@ -52,13 +52,11 @@ bool AudioProcessorValueTreeState::Parameter::isBoolean() const { return | |||
| void AudioProcessorValueTreeState::Parameter::valueChanged (float newValue) | |||
| { | |||
| if (lastValue == newValue) | |||
| if (approximatelyEqual ((float) lastValue, newValue)) | |||
| return; | |||
| lastValue = newValue; | |||
| if (onValueChanged != nullptr) | |||
| onValueChanged(); | |||
| NullCheckedInvocation::invoke (onValueChanged); | |||
| } | |||
| //============================================================================== | |||
| @@ -93,10 +91,8 @@ public: | |||
| void setDenormalisedValue (float value) | |||
| { | |||
| if (value == unnormalisedValue) | |||
| return; | |||
| setNormalisedValue (normalise (value)); | |||
| if (! approximatelyEqual (value, (float) unnormalisedValue)) | |||
| setNormalisedValue (normalise (value)); | |||
| } | |||
| float getDenormalisedValueForText (const String& text) const | |||
| @@ -119,9 +115,9 @@ public: | |||
| if (! needsUpdate.compare_exchange_strong (needsUpdateTestValue, false)) | |||
| return false; | |||
| if (auto valueProperty = tree.getPropertyPointer (key)) | |||
| if (auto* valueProperty = tree.getPropertyPointer (key)) | |||
| { | |||
| if ((float) *valueProperty != unnormalisedValue) | |||
| if (! approximatelyEqual ((float) *valueProperty, unnormalisedValue.load())) | |||
| { | |||
| ScopedValueSetter<bool> svs (ignoreParameterChangedCallbacks, true); | |||
| tree.setProperty (key, unnormalisedValue.load(), um); | |||
| @@ -144,7 +140,7 @@ private: | |||
| { | |||
| const auto newValue = denormalise (parameter.getValue()); | |||
| if (unnormalisedValue == newValue && ! listenersNeedCalling) | |||
| if (! listenersNeedCalling && approximatelyEqual ((float) unnormalisedValue, newValue)) | |||
| return; | |||
| unnormalisedValue = newValue; | |||
| @@ -84,7 +84,7 @@ void ParameterAttachment::callIfParameterValueChanged (float newDenormalisedValu | |||
| { | |||
| const auto newValue = normalise (newDenormalisedValue); | |||
| if (parameter.getValue() != newValue) | |||
| if (! approximatelyEqual (parameter.getValue(), newValue)) | |||
| callback (newValue); | |||
| } | |||
| @@ -722,7 +722,7 @@ private: | |||
| auto currentRate = currentDevice->getCurrentSampleRate(); | |||
| if (currentRate == 0) | |||
| if (exactlyEqual (currentRate, 0.0)) | |||
| currentRate = 48000.0; | |||
| for (auto bs : currentDevice->getAvailableBufferSizes()) | |||
| @@ -501,8 +501,8 @@ private: | |||
| if (numSamples == numSamplesCached | |||
| && numChannelsCached == numChans | |||
| && startTime == cachedStart | |||
| && timePerPixel == cachedTimePerPixel | |||
| && approximatelyEqual (startTime, cachedStart) | |||
| && approximatelyEqual (timePerPixel, cachedTimePerPixel) | |||
| && ! cacheNeedsRefilling) | |||
| { | |||
| return ! cacheNeedsRefilling; | |||
| @@ -79,7 +79,7 @@ void KeyboardComponentBase::setKeyWidth (float widthInPixels) | |||
| { | |||
| jassert (widthInPixels > 0); | |||
| if (keyWidth != widthInPixels) // Prevent infinite recursion if the width is being computed in a 'resized()' callback | |||
| if (! approximatelyEqual (keyWidth, widthInPixels)) // Prevent infinite recursion if the width is being computed in a 'resized()' callback | |||
| { | |||
| keyWidth = widthInPixels; | |||
| resized(); | |||
| @@ -130,7 +130,7 @@ void KeyboardComponentBase::setLowestVisibleKeyFloat (float noteNumber) | |||
| { | |||
| noteNumber = jlimit ((float) rangeStart, (float) rangeEnd, noteNumber); | |||
| if (noteNumber != firstKey) | |||
| if (! approximatelyEqual (noteNumber, firstKey)) | |||
| { | |||
| bool hasMoved = (((int) firstKey) != (int) noteNumber); | |||
| firstKey = noteNumber; | |||
| @@ -151,7 +151,7 @@ void KeyboardComponentBase::setBlackNoteLengthProportion (float ratio) noexcept | |||
| { | |||
| jassert (ratio >= 0.0f && ratio <= 1.0f); | |||
| if (blackNoteLengthRatio != ratio) | |||
| if (! approximatelyEqual (blackNoteLengthRatio, ratio)) | |||
| { | |||
| blackNoteLengthRatio = ratio; | |||
| resized(); | |||
| @@ -168,7 +168,7 @@ void KeyboardComponentBase::setBlackNoteWidthProportion (float ratio) noexcept | |||
| { | |||
| jassert (ratio >= 0.0f && ratio <= 1.0f); | |||
| if (blackNoteWidthRatio != ratio) | |||
| if (! approximatelyEqual (blackNoteWidthRatio, ratio)) | |||
| { | |||
| blackNoteWidthRatio = ratio; | |||
| resized(); | |||
| @@ -452,7 +452,7 @@ void KeyboardComponentBase::resized() | |||
| //============================================================================== | |||
| void KeyboardComponentBase::mouseWheelMove (const MouseEvent&, const MouseWheelDetails& wheel) | |||
| { | |||
| auto amount = (orientation == horizontalKeyboard && wheel.deltaX != 0) | |||
| auto amount = (orientation == horizontalKeyboard && ! approximatelyEqual (wheel.deltaX, 0.0f)) | |||
| ? wheel.deltaX : (orientation == verticalKeyboardFacingLeft ? wheel.deltaY | |||
| : -wheel.deltaY); | |||
| @@ -35,15 +35,16 @@ | |||
| #include "juce_box2d.h" | |||
| JUCE_BEGIN_IGNORE_WARNINGS_MSVC (6011) | |||
| JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wconversion", | |||
| "-Wsign-conversion", | |||
| JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wcast-align", | |||
| "-Wconversion", | |||
| "-Wfloat-conversion", | |||
| "-Wcast-align", | |||
| "-Wswitch-enum", | |||
| "-Wfloat-equal", | |||
| "-Wmaybe-uninitialized", | |||
| "-Wsign-conversion", | |||
| "-Wswitch-default", | |||
| "-Wswitch-enum", | |||
| "-Wunused-but-set-variable", | |||
| "-Wzero-as-null-pointer-constant", | |||
| "-Wmaybe-uninitialized") | |||
| "-Wzero-as-null-pointer-constant") | |||
| #include <cstdarg> | |||
| @@ -56,11 +56,12 @@ | |||
| #include <juce_graphics/juce_graphics.h> | |||
| JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wconversion", | |||
| "-Wdeprecated", | |||
| "-Wfloat-equal", | |||
| "-Wmaybe-uninitialized", | |||
| "-Wshadow-field", | |||
| "-Wzero-as-null-pointer-constant", | |||
| "-Wsign-conversion", | |||
| "-Wdeprecated", | |||
| "-Wmaybe-uninitialized") | |||
| "-Wzero-as-null-pointer-constant") | |||
| #include <climits> | |||
| #include <cfloat> | |||
| @@ -404,7 +404,7 @@ public: | |||
| auto endPtr = values.end(); | |||
| for (; e != endPtr; ++e) | |||
| if (elementToLookFor == *e) | |||
| if (exactlyEqual (elementToLookFor, *e)) | |||
| return true; | |||
| return false; | |||
| @@ -123,7 +123,7 @@ public: | |||
| auto* e = begin(); | |||
| for (auto& o : other) | |||
| if (! (*e++ == o)) | |||
| if (! exactlyEqual (*e++, o)) | |||
| return false; | |||
| return true; | |||
| @@ -201,7 +201,7 @@ struct var::VariantType | |||
| static int64 doubleToInt64 (const ValueUnion& data) noexcept { return (int64) data.doubleValue; } | |||
| static double doubleToDouble (const ValueUnion& data) noexcept { return data.doubleValue; } | |||
| static String doubleToString (const ValueUnion& data) { return serialiseDouble (data.doubleValue); } | |||
| static bool doubleToBool (const ValueUnion& data) noexcept { return data.doubleValue != 0.0; } | |||
| static bool doubleToBool (const ValueUnion& data) noexcept { return ! exactlyEqual (data.doubleValue, 0.0); } | |||
| static bool doubleEquals (const ValueUnion& data, const ValueUnion& otherData, const VariantType& otherType) noexcept | |||
| { | |||
| @@ -645,7 +645,7 @@ static int compare (const var& v1, const var& v2) | |||
| return v1.toString().compare (v2.toString()); | |||
| auto diff = static_cast<double> (v1) - static_cast<double> (v2); | |||
| return diff == 0 ? 0 : (diff < 0 ? -1 : 1); | |||
| return exactlyEqual (diff, 0.0) ? 0 : (diff < 0 ? -1 : 1); | |||
| } | |||
| bool operator== (const var& v1, const var& v2) { return v1.equals (v2); } | |||
| @@ -520,7 +520,7 @@ struct JavascriptEngine::RootObject : public DynamicObject | |||
| { | |||
| EqualsOp (const CodeLocation& l, ExpPtr& a, ExpPtr& b) noexcept : BinaryOperator (l, a, b, TokenTypes::equals) {} | |||
| var getWithUndefinedArg() const override { return true; } | |||
| var getWithDoubles (double a, double b) const override { return a == b; } | |||
| var getWithDoubles (double a, double b) const override { return exactlyEqual (a, b); } | |||
| var getWithInts (int64 a, int64 b) const override { return a == b; } | |||
| var getWithStrings (const String& a, const String& b) const override { return a == b; } | |||
| var getWithArrayOrObject (const var& a, const var& b) const override { return a == b; } | |||
| @@ -530,7 +530,7 @@ struct JavascriptEngine::RootObject : public DynamicObject | |||
| { | |||
| NotEqualsOp (const CodeLocation& l, ExpPtr& a, ExpPtr& b) noexcept : BinaryOperator (l, a, b, TokenTypes::notEquals) {} | |||
| var getWithUndefinedArg() const override { return false; } | |||
| var getWithDoubles (double a, double b) const override { return a != b; } | |||
| var getWithDoubles (double a, double b) const override { return ! exactlyEqual (a, b); } | |||
| var getWithInts (int64 a, int64 b) const override { return a != b; } | |||
| var getWithStrings (const String& a, const String& b) const override { return a != b; } | |||
| var getWithArrayOrObject (const var& a, const var& b) const override { return a != b; } | |||
| @@ -593,14 +593,14 @@ struct JavascriptEngine::RootObject : public DynamicObject | |||
| struct DivideOp : public BinaryOperator | |||
| { | |||
| DivideOp (const CodeLocation& l, ExpPtr& a, ExpPtr& b) noexcept : BinaryOperator (l, a, b, TokenTypes::divide) {} | |||
| var getWithDoubles (double a, double b) const override { return b != 0 ? a / b : std::numeric_limits<double>::infinity(); } | |||
| var getWithDoubles (double a, double b) const override { return exactlyEqual (b, 0.0) ? std::numeric_limits<double>::infinity() : a / b; } | |||
| var getWithInts (int64 a, int64 b) const override { return b != 0 ? var ((double) a / (double) b) : var (std::numeric_limits<double>::infinity()); } | |||
| }; | |||
| struct ModuloOp : public BinaryOperator | |||
| { | |||
| ModuloOp (const CodeLocation& l, ExpPtr& a, ExpPtr& b) noexcept : BinaryOperator (l, a, b, TokenTypes::modulo) {} | |||
| var getWithDoubles (double a, double b) const override { return b != 0 ? fmod (a, b) : std::numeric_limits<double>::infinity(); } | |||
| var getWithDoubles (double a, double b) const override { return exactlyEqual (b, 0.0) ? std::numeric_limits<double>::infinity() : fmod (a, b); } | |||
| var getWithInts (int64 a, int64 b) const override { return b != 0 ? var (a % b) : var (std::numeric_limits<double>::infinity()); } | |||
| }; | |||
| @@ -86,6 +86,29 @@ using uint32 = unsigned int; | |||
| using ssize_t = pointer_sized_int; | |||
| #endif | |||
| /** Returns true if the two numbers are approximately equal. This is useful for floating-point | |||
| and double comparisons. | |||
| */ | |||
| template <typename Type> | |||
| bool approximatelyEqual (Type a, Type b) noexcept | |||
| { | |||
| return std::abs (a - b) <= (std::numeric_limits<Type>::epsilon() * std::max (a, b)) | |||
| || std::abs (a - b) < std::numeric_limits<Type>::min(); | |||
| } | |||
| /** Equivalent to operator==, but suppresses float-equality warnings. | |||
| This allows code to be explicit about float-equality checks that are known to have the correct | |||
| semantics. | |||
| */ | |||
| template <typename Type> | |||
| constexpr bool exactlyEqual (Type a, Type b) | |||
| { | |||
| JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wfloat-equal") | |||
| return a == b; | |||
| JUCE_END_IGNORE_WARNINGS_GCC_LIKE | |||
| } | |||
| //============================================================================== | |||
| // Some indispensable min/max functions | |||
| @@ -126,7 +149,7 @@ constexpr Type jmap (Type value0To1, Type targetRangeMin, Type targetRangeMax) | |||
| template <typename Type> | |||
| Type jmap (Type sourceValue, Type sourceRangeMin, Type sourceRangeMax, Type targetRangeMin, Type targetRangeMax) | |||
| { | |||
| jassert (sourceRangeMax != sourceRangeMin); // mapping from a range of zero will produce NaN! | |||
| jassert (! approximatelyEqual (sourceRangeMax, sourceRangeMin)); // mapping from a range of zero will produce NaN! | |||
| return targetRangeMin + ((targetRangeMax - targetRangeMin) * (sourceValue - sourceRangeMin)) / (sourceRangeMax - sourceRangeMin); | |||
| } | |||
| @@ -317,16 +340,6 @@ bool isWithin (Type a, Type b, Type tolerance) noexcept | |||
| return std::abs (a - b) <= tolerance; | |||
| } | |||
| /** Returns true if the two numbers are approximately equal. This is useful for floating-point | |||
| and double comparisons. | |||
| */ | |||
| template <typename Type> | |||
| bool approximatelyEqual (Type a, Type b) noexcept | |||
| { | |||
| return std::abs (a - b) <= (std::numeric_limits<Type>::epsilon() * std::max (a, b)) | |||
| || std::abs (a - b) < std::numeric_limits<Type>::min(); | |||
| } | |||
| //============================================================================== | |||
| /** Handy function for avoiding unused variables warning. */ | |||
| template <typename... Types> | |||
| @@ -128,7 +128,7 @@ public: | |||
| auto proportion = clampTo0To1 ((v - start) / (end - start)); | |||
| if (skew == static_cast<ValueType> (1)) | |||
| if (exactlyEqual (skew, static_cast<ValueType> (1))) | |||
| return proportion; | |||
| if (! symmetricSkew) | |||
| @@ -154,7 +154,7 @@ public: | |||
| if (! symmetricSkew) | |||
| { | |||
| if (skew != static_cast<ValueType> (1) && proportion > ValueType()) | |||
| if (! exactlyEqual (skew, static_cast<ValueType> (1)) && proportion > ValueType()) | |||
| proportion = std::exp (std::log (proportion) / skew); | |||
| return start + (end - start) * proportion; | |||
| @@ -162,7 +162,7 @@ public: | |||
| auto distanceFromMiddle = static_cast<ValueType> (2) * proportion - static_cast<ValueType> (1); | |||
| if (skew != static_cast<ValueType> (1) && distanceFromMiddle != static_cast<ValueType> (0)) | |||
| if (! exactlyEqual (skew, static_cast<ValueType> (1)) && ! exactlyEqual (distanceFromMiddle, static_cast<ValueType> (0))) | |||
| distanceFromMiddle = std::exp (std::log (std::abs (distanceFromMiddle)) / skew) | |||
| * (distanceFromMiddle < ValueType() ? static_cast<ValueType> (-1) | |||
| : static_cast<ValueType> (1)); | |||
| @@ -250,7 +250,7 @@ private: | |||
| // If you hit this assertion then either your normalisation function is not working | |||
| // correctly or your input is out of the expected bounds. | |||
| jassert (clampedValue == value); | |||
| jassert (exactlyEqual (clampedValue, value)); | |||
| return clampedValue; | |||
| } | |||
| @@ -103,7 +103,7 @@ float Random::nextFloat() noexcept | |||
| { | |||
| auto result = static_cast<float> (static_cast<uint32> (nextInt())) | |||
| / (static_cast<float> (std::numeric_limits<uint32>::max()) + 1.0f); | |||
| return result == 1.0f ? 1.0f - std::numeric_limits<float>::epsilon() : result; | |||
| return jmin (result, 1.0f - std::numeric_limits<float>::epsilon()); | |||
| } | |||
| double Random::nextDouble() noexcept | |||
| @@ -86,7 +86,7 @@ public: | |||
| constexpr inline ValueType getEnd() const noexcept { return end; } | |||
| /** Returns true if the range has a length of zero. */ | |||
| constexpr inline bool isEmpty() const noexcept { return start == end; } | |||
| constexpr inline bool isEmpty() const noexcept { return exactlyEqual (start, end); } | |||
| //============================================================================== | |||
| /** Changes the start position of the range, leaving the end position unchanged. | |||
| @@ -198,8 +198,13 @@ public: | |||
| return Range (start - amountToSubtract, end - amountToSubtract); | |||
| } | |||
| constexpr bool operator== (Range other) const noexcept { return start == other.start && end == other.end; } | |||
| constexpr bool operator!= (Range other) const noexcept { return start != other.start || end != other.end; } | |||
| constexpr bool operator== (Range other) const noexcept | |||
| { | |||
| const auto tie = [] (const Range& r) { return std::tie (r.start, r.end); }; | |||
| return tie (*this) == tie (other); | |||
| } | |||
| constexpr bool operator!= (Range other) const noexcept { return ! operator== (other); } | |||
| //============================================================================== | |||
| /** Returns true if the given position lies inside this range. | |||
| @@ -138,8 +138,8 @@ public: | |||
| expectEquals (mi.readString(), randomString); | |||
| expect (mi.readInt64() == randomInt64); | |||
| expect (mi.readInt64BigEndian() == randomInt64); | |||
| expect (mi.readDouble() == randomDouble); | |||
| expect (mi.readDoubleBigEndian() == randomDouble); | |||
| expectEquals (mi.readDouble(), randomDouble); | |||
| expectEquals (mi.readDoubleBigEndian(), randomDouble); | |||
| const MemoryBlock data ("abcdefghijklmnopqrstuvwxyz", 26); | |||
| MemoryInputStream stream (data, true); | |||
| @@ -31,7 +31,8 @@ | |||
| #define JUCE_NTH_ARG_(_00, _01, _02, _03, _04, _05, _06, _07, _08, _09, \ | |||
| _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, \ | |||
| _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, \ | |||
| _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, N, ...)\ | |||
| _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, \ | |||
| _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, N, ...)\ | |||
| N | |||
| #define JUCE_EACH_00_(FN) | |||
| @@ -74,10 +75,30 @@ | |||
| #define JUCE_EACH_37_(FN, X, ...) FN(X) JUCE_EACH_36_(FN, __VA_ARGS__) | |||
| #define JUCE_EACH_38_(FN, X, ...) FN(X) JUCE_EACH_37_(FN, __VA_ARGS__) | |||
| #define JUCE_EACH_39_(FN, X, ...) FN(X) JUCE_EACH_38_(FN, __VA_ARGS__) | |||
| #define JUCE_EACH_40_(FN, X, ...) FN(X) JUCE_EACH_39_(FN, __VA_ARGS__) | |||
| #define JUCE_EACH_41_(FN, X, ...) FN(X) JUCE_EACH_40_(FN, __VA_ARGS__) | |||
| #define JUCE_EACH_42_(FN, X, ...) FN(X) JUCE_EACH_41_(FN, __VA_ARGS__) | |||
| #define JUCE_EACH_43_(FN, X, ...) FN(X) JUCE_EACH_42_(FN, __VA_ARGS__) | |||
| #define JUCE_EACH_44_(FN, X, ...) FN(X) JUCE_EACH_43_(FN, __VA_ARGS__) | |||
| #define JUCE_EACH_45_(FN, X, ...) FN(X) JUCE_EACH_44_(FN, __VA_ARGS__) | |||
| #define JUCE_EACH_46_(FN, X, ...) FN(X) JUCE_EACH_45_(FN, __VA_ARGS__) | |||
| #define JUCE_EACH_47_(FN, X, ...) FN(X) JUCE_EACH_46_(FN, __VA_ARGS__) | |||
| #define JUCE_EACH_48_(FN, X, ...) FN(X) JUCE_EACH_47_(FN, __VA_ARGS__) | |||
| #define JUCE_EACH_49_(FN, X, ...) FN(X) JUCE_EACH_48_(FN, __VA_ARGS__) | |||
| /** Apply the macro FN to each of the other arguments. */ | |||
| #define JUCE_EACH(FN, ...) \ | |||
| JUCE_NTH_ARG_(, __VA_ARGS__, \ | |||
| JUCE_EACH_49_, \ | |||
| JUCE_EACH_48_, \ | |||
| JUCE_EACH_47_, \ | |||
| JUCE_EACH_46_, \ | |||
| JUCE_EACH_45_, \ | |||
| JUCE_EACH_44_, \ | |||
| JUCE_EACH_43_, \ | |||
| JUCE_EACH_42_, \ | |||
| JUCE_EACH_41_, \ | |||
| JUCE_EACH_40_, \ | |||
| JUCE_EACH_39_, \ | |||
| JUCE_EACH_38_, \ | |||
| JUCE_EACH_37_, \ | |||
| @@ -134,7 +134,7 @@ double CharacterFunctions::mulexp10 (const double value, int exponent) noexcept | |||
| if (exponent == 0) | |||
| return value; | |||
| if (value == 0.0) | |||
| if (exactlyEqual (value, 0.0)) | |||
| return 0; | |||
| const bool negative = (exponent < 0); | |||
| @@ -2266,7 +2266,7 @@ static String serialiseDouble (double input) | |||
| int intInput = (int) input; | |||
| if ((double) intInput == input) | |||
| if (exactlyEqual ((double) intInput, input)) | |||
| return { input, 1 }; | |||
| auto numberOfDecimalPlaces = [absInput] | |||
| @@ -2567,16 +2567,16 @@ public: | |||
| beginTest ("Numeric conversions"); | |||
| expect (String().getIntValue() == 0); | |||
| expect (String().getDoubleValue() == 0.0); | |||
| expect (String().getFloatValue() == 0.0f); | |||
| expectEquals (String().getDoubleValue(), 0.0); | |||
| expectEquals (String().getFloatValue(), 0.0f); | |||
| expect (s.getIntValue() == 12345678); | |||
| expect (s.getLargeIntValue() == (int64) 12345678); | |||
| expect (s.getDoubleValue() == 12345678.0); | |||
| expect (s.getFloatValue() == 12345678.0f); | |||
| expectEquals (s.getDoubleValue(), 12345678.0); | |||
| expectEquals (s.getFloatValue(), 12345678.0f); | |||
| expect (String (-1234).getIntValue() == -1234); | |||
| expect (String ((int64) -1234).getLargeIntValue() == -1234); | |||
| expect (String (-1234.56).getDoubleValue() == -1234.56); | |||
| expect (String (-1234.56f).getFloatValue() == -1234.56f); | |||
| expectEquals (String (-1234.56).getDoubleValue(), -1234.56); | |||
| expectEquals (String (-1234.56f).getFloatValue(), -1234.56f); | |||
| expect (String (std::numeric_limits<int>::max()).getIntValue() == std::numeric_limits<int>::max()); | |||
| expect (String (std::numeric_limits<int>::min()).getIntValue() == std::numeric_limits<int>::min()); | |||
| expect (String (std::numeric_limits<int64>::max()).getLargeIntValue() == std::numeric_limits<int64>::max()); | |||
| @@ -1117,7 +1117,7 @@ public: | |||
| { | |||
| jassert (numberOfSignificantFigures > 0); | |||
| if (number == 0) | |||
| if (exactlyEqual (number, DecimalType())) | |||
| { | |||
| if (numberOfSignificantFigures > 1) | |||
| { | |||
| @@ -417,7 +417,7 @@ public: | |||
| class AtomicTester | |||
| { | |||
| public: | |||
| AtomicTester() {} | |||
| AtomicTester() = default; | |||
| static void testInteger (UnitTest& test) | |||
| { | |||
| @@ -460,17 +460,17 @@ public: | |||
| /* These are some simple test cases to check the atomics - let me know | |||
| if any of these assertions fail on your system! | |||
| */ | |||
| test.expect (a.get() == (Type) 101); | |||
| test.expect (exactlyEqual (a.get(), (Type) 101)); | |||
| test.expect (! a.compareAndSetBool ((Type) 300, (Type) 200)); | |||
| test.expect (a.get() == (Type) 101); | |||
| test.expect (exactlyEqual (a.get(), (Type) 101)); | |||
| test.expect (a.compareAndSetBool ((Type) 200, a.get())); | |||
| test.expect (a.get() == (Type) 200); | |||
| test.expect (exactlyEqual (a.get(), (Type) 200)); | |||
| test.expect (a.exchange ((Type) 300) == (Type) 200); | |||
| test.expect (a.get() == (Type) 300); | |||
| test.expect (exactlyEqual (a.exchange ((Type) 300), (Type) 200)); | |||
| test.expect (exactlyEqual (a.get(), (Type) 300)); | |||
| b = a; | |||
| test.expect (b.get() == a.get()); | |||
| test.expect (exactlyEqual (b.get(), a.get())); | |||
| } | |||
| }; | |||
| }; | |||
| @@ -54,8 +54,16 @@ RelativeTime RelativeTime::operator-= (double secs) noexcept { numSeconds | |||
| JUCE_API RelativeTime JUCE_CALLTYPE operator+ (RelativeTime t1, RelativeTime t2) noexcept { return t1 += t2; } | |||
| JUCE_API RelativeTime JUCE_CALLTYPE operator- (RelativeTime t1, RelativeTime t2) noexcept { return t1 -= t2; } | |||
| JUCE_API bool JUCE_CALLTYPE operator== (RelativeTime t1, RelativeTime t2) noexcept { return t1.inSeconds() == t2.inSeconds(); } | |||
| JUCE_API bool JUCE_CALLTYPE operator!= (RelativeTime t1, RelativeTime t2) noexcept { return t1.inSeconds() != t2.inSeconds(); } | |||
| JUCE_API bool JUCE_CALLTYPE operator== (RelativeTime t1, RelativeTime t2) noexcept | |||
| { | |||
| return exactlyEqual (t1.inSeconds(), t2.inSeconds()); | |||
| } | |||
| JUCE_API bool JUCE_CALLTYPE operator!= (RelativeTime t1, RelativeTime t2) noexcept | |||
| { | |||
| return ! (t1 == t2); | |||
| } | |||
| JUCE_API bool JUCE_CALLTYPE operator> (RelativeTime t1, RelativeTime t2) noexcept { return t1.inSeconds() > t2.inSeconds(); } | |||
| JUCE_API bool JUCE_CALLTYPE operator< (RelativeTime t1, RelativeTime t2) noexcept { return t1.inSeconds() < t2.inSeconds(); } | |||
| JUCE_API bool JUCE_CALLTYPE operator>= (RelativeTime t1, RelativeTime t2) noexcept { return t1.inSeconds() >= t2.inSeconds(); } | |||
| @@ -150,7 +150,7 @@ public: | |||
| template <class ValueType> | |||
| void expectEquals (ValueType actual, ValueType expected, String failureMessage = String()) | |||
| { | |||
| bool result = actual == expected; | |||
| bool result = exactlyEqual (actual, expected); | |||
| expectResultAndPrint (actual, expected, result, "", failureMessage); | |||
| } | |||
| @@ -160,7 +160,7 @@ public: | |||
| template <class ValueType> | |||
| void expectNotEquals (ValueType value, ValueType valueToCompareTo, String failureMessage = String()) | |||
| { | |||
| bool result = value != valueToCompareTo; | |||
| bool result = ! exactlyEqual (value, valueToCompareTo); | |||
| expectResultAndPrint (value, valueToCompareTo, result, "unequal to", failureMessage); | |||
| } | |||
| @@ -245,7 +245,7 @@ inline CachedValue<Type>& CachedValue<Type>::operator= (const Type& newValue) | |||
| template <typename Type> | |||
| inline void CachedValue<Type>::setValue (const Type& newValue, UndoManager* undoManagerToUse) | |||
| { | |||
| if (cachedValue != newValue || isUsingDefault()) | |||
| if (! exactlyEqual (cachedValue, newValue) || isUsingDefault()) | |||
| { | |||
| cachedValue = newValue; | |||
| targetTree.setProperty (targetProperty, VariantConverter<Type>::toVar (newValue), undoManagerToUse); | |||
| @@ -28,6 +28,9 @@ namespace juce | |||
| namespace dsp | |||
| { | |||
| template <typename SampleType> | |||
| String& operator<< (String& str, SIMDRegister<SampleType>) { return str; } | |||
| template <typename SampleType> | |||
| class AudioBlockUnitTests : public UnitTest | |||
| { | |||
| @@ -79,25 +82,25 @@ public: | |||
| resetBlocks(); | |||
| expect (block != otherBlock); | |||
| expect (block.getSample (0, 0) == SampleType (1.0)); | |||
| expect (block.getSample (0, 4) == SampleType (5.0)); | |||
| expect (otherBlock.getSample (0, 0) == SampleType (-1.0)); | |||
| expect (otherBlock.getSample (0, 3) == SampleType (-4.0)); | |||
| expectEquals (block.getSample (0, 0), SampleType (1.0)); | |||
| expectEquals (block.getSample (0, 4), SampleType (5.0)); | |||
| expectEquals (otherBlock.getSample (0, 0), SampleType (-1.0)); | |||
| expectEquals (otherBlock.getSample (0, 3), SampleType (-4.0)); | |||
| block.swap (otherBlock); | |||
| expect (block != otherBlock); | |||
| expect (otherBlock.getSample (0, 0) == SampleType (1.0)); | |||
| expect (otherBlock.getSample (0, 4) == SampleType (5.0)); | |||
| expect (block.getSample (0, 0) == SampleType (-1.0)); | |||
| expect (block.getSample (0, 3) == SampleType (-4.0)); | |||
| expectEquals (otherBlock.getSample (0, 0), SampleType (1.0)); | |||
| expectEquals (otherBlock.getSample (0, 4), SampleType (5.0)); | |||
| expectEquals (block.getSample (0, 0), SampleType (-1.0)); | |||
| expectEquals (block.getSample (0, 3), SampleType (-4.0)); | |||
| block.swap (otherBlock); | |||
| expect (block.getSample (0, 0) == SampleType (1.0)); | |||
| expect (block.getSample (0, 4) == SampleType (5.0)); | |||
| expect (otherBlock.getSample (0, 0) == SampleType (-1.0)); | |||
| expect (otherBlock.getSample (0, 3) == SampleType (-4.0)); | |||
| expectEquals (block.getSample (0, 0), SampleType (1.0)); | |||
| expectEquals (block.getSample (0, 4), SampleType (5.0)); | |||
| expectEquals (otherBlock.getSample (0, 0), SampleType (-1.0)); | |||
| expectEquals (otherBlock.getSample (0, 3), SampleType (-4.0)); | |||
| } | |||
| beginTest ("Getters and setters"); | |||
| @@ -107,49 +110,49 @@ public: | |||
| expectEquals ((int) block.getNumChannels(), (int) data.size()); | |||
| expectEquals ((int) block.getNumSamples(), numSamples); | |||
| expect (block.getChannelPointer (0)[2] == SampleType (3.0)); | |||
| expectEquals (block.getChannelPointer (0)[2], SampleType (3.0)); | |||
| block.getChannelPointer (0)[2] = SampleType (999.0); | |||
| expect (block.getChannelPointer (0)[2] == SampleType (999.0)); | |||
| expectEquals (block.getChannelPointer (0)[2], SampleType (999.0)); | |||
| expect (block.getSample (0, 4) == SampleType (5.0)); | |||
| expect (block.getSample (1, 4) == SampleType (11.0)); | |||
| expectEquals (block.getSample (0, 4), SampleType (5.0)); | |||
| expectEquals (block.getSample (1, 4), SampleType (11.0)); | |||
| expect (block.getSingleChannelBlock (1).getSample (0, 3) == block.getSample (1, 3)); | |||
| expectEquals (block.getSingleChannelBlock (1).getSample (0, 3), block.getSample (1, 3)); | |||
| expect (block.getSubsetChannelBlock (0, 2).getSample (1, 3) == block.getSample (1, 3)); | |||
| expect (block.getSubsetChannelBlock (1, 1).getSample (0, 3) == block.getSample (1, 3)); | |||
| expectEquals (block.getSubsetChannelBlock (0, 2).getSample (1, 3), block.getSample (1, 3)); | |||
| expectEquals (block.getSubsetChannelBlock (1, 1).getSample (0, 3), block.getSample (1, 3)); | |||
| block.setSample (1, 1, SampleType (777.0)); | |||
| expect (block.getSample (1, 1) == SampleType (777.0)); | |||
| expectEquals (block.getSample (1, 1), SampleType (777.0)); | |||
| block.addSample (1, 1, SampleType (1.0)); | |||
| expect (block.getSample (1, 1) == SampleType (778.0)); | |||
| expectEquals (block.getSample (1, 1), SampleType (778.0)); | |||
| } | |||
| beginTest ("Basic copying"); | |||
| { | |||
| block.clear(); | |||
| expect (block.getSample (0, 2) == SampleType (0.0)); | |||
| expect (block.getSample (1, 4) == SampleType (0.0)); | |||
| expectEquals (block.getSample (0, 2), SampleType (0.0)); | |||
| expectEquals (block.getSample (1, 4), SampleType (0.0)); | |||
| block.fill ((NumericType) 456.0); | |||
| expect (block.getSample (0, 2) == SampleType (456.0)); | |||
| expect (block.getSample (1, 4) == SampleType (456.0)); | |||
| expectEquals (block.getSample (0, 2), SampleType (456.0)); | |||
| expectEquals (block.getSample (1, 4), SampleType (456.0)); | |||
| block.copyFrom (otherBlock); | |||
| expect (block != otherBlock); | |||
| expect (block.getSample (0, 2) == otherBlock.getSample (0, 2)); | |||
| expect (block.getSample (1, 4) == otherBlock.getSample (1, 4)); | |||
| expectEquals (block.getSample (0, 2), otherBlock.getSample (0, 2)); | |||
| expectEquals (block.getSample (1, 4), otherBlock.getSample (1, 4)); | |||
| resetBlocks(); | |||
| SampleType testSample1 = block.getSample (0, 2); | |||
| SampleType testSample2 = block.getSample (1, 3); | |||
| expect (testSample1 != block.getSample (0, 4)); | |||
| expect (testSample2 != block.getSample (1, 5)); | |||
| expectNotEquals (testSample1, block.getSample (0, 4)); | |||
| expectNotEquals (testSample2, block.getSample (1, 5)); | |||
| block.move (0, 2); | |||
| expect (block.getSample (0, 4) == testSample1); | |||
| expect (block.getSample (1, 5) == testSample2); | |||
| expectEquals (block.getSample (0, 4), testSample1); | |||
| expectEquals (block.getSample (1, 5), testSample2); | |||
| } | |||
| beginTest ("Addition"); | |||
| @@ -157,22 +160,22 @@ public: | |||
| resetBlocks(); | |||
| block.add ((NumericType) 15.0); | |||
| expect (block.getSample (0, 4) == SampleType (20.0)); | |||
| expect (block.getSample (1, 4) == SampleType (26.0)); | |||
| expectEquals (block.getSample (0, 4), SampleType (20.0)); | |||
| expectEquals (block.getSample (1, 4), SampleType (26.0)); | |||
| block.add (otherBlock); | |||
| expect (block.getSample (0, 4) == SampleType (15.0)); | |||
| expect (block.getSample (1, 4) == SampleType (15.0)); | |||
| expectEquals (block.getSample (0, 4), SampleType (15.0)); | |||
| expectEquals (block.getSample (1, 4), SampleType (15.0)); | |||
| block.replaceWithSumOf (otherBlock, (NumericType) 9.0); | |||
| expect (block.getSample (0, 4) == SampleType (4.0)); | |||
| expect (block.getSample (1, 4) == SampleType (-2.0)); | |||
| expectEquals (block.getSample (0, 4), SampleType (4.0)); | |||
| expectEquals (block.getSample (1, 4), SampleType (-2.0)); | |||
| resetBlocks(); | |||
| block.replaceWithSumOf (block, otherBlock); | |||
| expect (block.getSample (0, 4) == SampleType (0.0)); | |||
| expect (block.getSample (1, 4) == SampleType (0.0)); | |||
| expectEquals (block.getSample (0, 4), SampleType (0.0)); | |||
| expectEquals (block.getSample (1, 4), SampleType (0.0)); | |||
| } | |||
| beginTest ("Subtraction"); | |||
| @@ -180,22 +183,22 @@ public: | |||
| resetBlocks(); | |||
| block.subtract ((NumericType) 15.0); | |||
| expect (block.getSample (0, 4) == SampleType (-10.0)); | |||
| expect (block.getSample (1, 4) == SampleType (-4.0)); | |||
| expectEquals (block.getSample (0, 4), SampleType (-10.0)); | |||
| expectEquals (block.getSample (1, 4), SampleType (-4.0)); | |||
| block.subtract (otherBlock); | |||
| expect (block.getSample (0, 4) == SampleType (-5.0)); | |||
| expect (block.getSample (1, 4) == SampleType (7.0)); | |||
| expectEquals (block.getSample (0, 4), SampleType (-5.0)); | |||
| expectEquals (block.getSample (1, 4), SampleType (7.0)); | |||
| block.replaceWithDifferenceOf (otherBlock, (NumericType) 9.0); | |||
| expect (block.getSample (0, 4) == SampleType (-14.0)); | |||
| expect (block.getSample (1, 4) == SampleType (-20.0)); | |||
| expectEquals (block.getSample (0, 4), SampleType (-14.0)); | |||
| expectEquals (block.getSample (1, 4), SampleType (-20.0)); | |||
| resetBlocks(); | |||
| block.replaceWithDifferenceOf (block, otherBlock); | |||
| expect (block.getSample (0, 4) == SampleType (10.0)); | |||
| expect (block.getSample (1, 4) == SampleType (22.0)); | |||
| expectEquals (block.getSample (0, 4), SampleType (10.0)); | |||
| expectEquals (block.getSample (1, 4), SampleType (22.0)); | |||
| } | |||
| beginTest ("Multiplication"); | |||
| @@ -203,22 +206,22 @@ public: | |||
| resetBlocks(); | |||
| block.multiplyBy ((NumericType) 10.0); | |||
| expect (block.getSample (0, 4) == SampleType (50.0)); | |||
| expect (block.getSample (1, 4) == SampleType (110.0)); | |||
| expectEquals (block.getSample (0, 4), SampleType (50.0)); | |||
| expectEquals (block.getSample (1, 4), SampleType (110.0)); | |||
| block.multiplyBy (otherBlock); | |||
| expect (block.getSample (0, 4) == SampleType (-250.0)); | |||
| expect (block.getSample (1, 4) == SampleType (-1210.0)); | |||
| expectEquals (block.getSample (0, 4), SampleType (-250.0)); | |||
| expectEquals (block.getSample (1, 4), SampleType (-1210.0)); | |||
| block.replaceWithProductOf (otherBlock, (NumericType) 3.0); | |||
| expect (block.getSample (0, 4) == SampleType (-15.0)); | |||
| expect (block.getSample (1, 4) == SampleType (-33.0)); | |||
| expectEquals (block.getSample (0, 4), SampleType (-15.0)); | |||
| expectEquals (block.getSample (1, 4), SampleType (-33.0)); | |||
| resetBlocks(); | |||
| block.replaceWithProductOf (block, otherBlock); | |||
| expect (block.getSample (0, 4) == SampleType (-25.0)); | |||
| expect (block.getSample (1, 4) == SampleType (-121.0)); | |||
| expectEquals (block.getSample (0, 4), SampleType (-25.0)); | |||
| expectEquals (block.getSample (1, 4), SampleType (-121.0)); | |||
| } | |||
| beginTest ("Multiply add"); | |||
| @@ -226,12 +229,12 @@ public: | |||
| resetBlocks(); | |||
| block.addProductOf (otherBlock, (NumericType) -1.0); | |||
| expect (block.getSample (0, 4) == SampleType (10.0)); | |||
| expect (block.getSample (1, 4) == SampleType (22.0)); | |||
| expectEquals (block.getSample (0, 4), SampleType (10.0)); | |||
| expectEquals (block.getSample (1, 4), SampleType (22.0)); | |||
| block.addProductOf (otherBlock, otherBlock); | |||
| expect (block.getSample (0, 4) == SampleType (35.0)); | |||
| expect (block.getSample (1, 4) == SampleType (143.0)); | |||
| expectEquals (block.getSample (0, 4), SampleType (35.0)); | |||
| expectEquals (block.getSample (1, 4), SampleType (143.0)); | |||
| } | |||
| beginTest ("Negative abs min max"); | |||
| @@ -240,68 +243,68 @@ public: | |||
| otherBlock.negate(); | |||
| block.add (otherBlock); | |||
| expect (block.getSample (0, 4) == SampleType (10.0)); | |||
| expect (block.getSample (1, 4) == SampleType (22.0)); | |||
| expectEquals (block.getSample (0, 4), SampleType (10.0)); | |||
| expectEquals (block.getSample (1, 4), SampleType (22.0)); | |||
| block.replaceWithNegativeOf (otherBlock); | |||
| expect (block.getSample (0, 4) == SampleType (-5.0)); | |||
| expect (block.getSample (1, 4) == SampleType (-11.0)); | |||
| expectEquals (block.getSample (0, 4), SampleType (-5.0)); | |||
| expectEquals (block.getSample (1, 4), SampleType (-11.0)); | |||
| block.clear(); | |||
| otherBlock.negate(); | |||
| block.replaceWithAbsoluteValueOf (otherBlock); | |||
| expect (block.getSample (0, 4) == SampleType (5.0)); | |||
| expect (block.getSample (1, 4) == SampleType (11.0)); | |||
| expectEquals (block.getSample (0, 4), SampleType (5.0)); | |||
| expectEquals (block.getSample (1, 4), SampleType (11.0)); | |||
| resetBlocks(); | |||
| block.replaceWithMinOf (block, otherBlock); | |||
| expect (block.getSample (0, 4) == SampleType (-5.0)); | |||
| expect (block.getSample (1, 4) == SampleType (-11.0)); | |||
| expectEquals (block.getSample (0, 4), SampleType (-5.0)); | |||
| expectEquals (block.getSample (1, 4), SampleType (-11.0)); | |||
| resetBlocks(); | |||
| block.replaceWithMaxOf (block, otherBlock); | |||
| expect (block.getSample (0, 4) == SampleType (5.0)); | |||
| expect (block.getSample (1, 4) == SampleType (11.0)); | |||
| expectEquals (block.getSample (0, 4), SampleType (5.0)); | |||
| expectEquals (block.getSample (1, 4), SampleType (11.0)); | |||
| resetBlocks(); | |||
| auto range = block.findMinAndMax(); | |||
| expect (SampleType (range.getStart()) == SampleType (1.0)); | |||
| expect (SampleType (range.getEnd()) == SampleType (12.0)); | |||
| expectEquals (SampleType (range.getStart()), SampleType (1.0)); | |||
| expectEquals (SampleType (range.getEnd()), SampleType (12.0)); | |||
| } | |||
| beginTest ("Operators"); | |||
| { | |||
| resetBlocks(); | |||
| block += (NumericType) 10.0; | |||
| expect (block.getSample (0, 4) == SampleType (15.0)); | |||
| expect (block.getSample (1, 4) == SampleType (21.0)); | |||
| expectEquals (block.getSample (0, 4), SampleType (15.0)); | |||
| expectEquals (block.getSample (1, 4), SampleType (21.0)); | |||
| block += otherBlock; | |||
| expect (block.getSample (0, 4) == SampleType (10.0)); | |||
| expect (block.getSample (1, 4) == SampleType (10.0)); | |||
| expectEquals (block.getSample (0, 4), SampleType (10.0)); | |||
| expectEquals (block.getSample (1, 4), SampleType (10.0)); | |||
| resetBlocks(); | |||
| block -= (NumericType) 10.0; | |||
| expect (block.getSample (0, 4) == SampleType (-5.0)); | |||
| expect (block.getSample (1, 4) == SampleType (1.0)); | |||
| expectEquals (block.getSample (0, 4), SampleType (-5.0)); | |||
| expectEquals (block.getSample (1, 4), SampleType (1.0)); | |||
| block -= otherBlock; | |||
| expect (block.getSample (0, 4) == SampleType (0.0)); | |||
| expect (block.getSample (1, 4) == SampleType (12.0)); | |||
| expectEquals (block.getSample (0, 4), SampleType (0.0)); | |||
| expectEquals (block.getSample (1, 4), SampleType (12.0)); | |||
| resetBlocks(); | |||
| block *= (NumericType) 10.0; | |||
| expect (block.getSample (0, 4) == SampleType (50.0)); | |||
| expect (block.getSample (1, 4) == SampleType (110.0)); | |||
| expectEquals (block.getSample (0, 4), SampleType (50.0)); | |||
| expectEquals (block.getSample (1, 4), SampleType (110.0)); | |||
| block *= otherBlock; | |||
| expect (block.getSample (0, 4) == SampleType (-250.0)); | |||
| expect (block.getSample (1, 4) == SampleType (-1210.0)); | |||
| expectEquals (block.getSample (0, 4), SampleType (-250.0)); | |||
| expectEquals (block.getSample (1, 4), SampleType (-1210.0)); | |||
| } | |||
| beginTest ("Process"); | |||
| { | |||
| resetBlocks(); | |||
| AudioBlock<SampleType>::process (block, otherBlock, [] (SampleType x) { return x + (NumericType) 1.0; }); | |||
| expect (otherBlock.getSample (0, 4) == SampleType (6.0)); | |||
| expect (otherBlock.getSample (1, 4) == SampleType (12.0)); | |||
| expectEquals (otherBlock.getSample (0, 4), SampleType (6.0)); | |||
| expectEquals (otherBlock.getSample (1, 4), SampleType (12.0)); | |||
| } | |||
| beginTest ("Copying"); | |||
| @@ -117,19 +117,12 @@ public: | |||
| template <typename type> | |||
| static bool allValuesEqualTo (const SIMDRegister<type>& vec, const type scalar) | |||
| { | |||
| #ifdef _MSC_VER | |||
| __declspec(align(sizeof (SIMDRegister<type>))) type elements[SIMDRegister<type>::SIMDNumElements]; | |||
| #else | |||
| type elements[SIMDRegister<type>::SIMDNumElements] __attribute__((aligned(sizeof (SIMDRegister<type>)))); | |||
| #endif | |||
| alignas (sizeof (SIMDRegister<type>)) type elements[SIMDRegister<type>::SIMDNumElements]; | |||
| vec.copyToRawArray (elements); | |||
| // as we do not want to rely on the access operator we cast this to a primitive pointer | |||
| for (size_t i = 0; i < SIMDRegister<type>::SIMDNumElements; ++i) | |||
| if (elements[i] != scalar) return false; | |||
| return true; | |||
| return std::all_of (std::begin (elements), std::end (elements), [scalar] (const auto x) { return exactlyEqual (x, scalar); }); | |||
| } | |||
| template <typename type> | |||
| @@ -307,7 +300,7 @@ public: | |||
| const SIMDRegister<type>& b = a; | |||
| for (size_t i = 0; i < SIMDRegister<type>::SIMDNumElements; ++i) | |||
| u.expect (b[i] == array[i]); | |||
| u.expect (exactlyEqual (b[i], array[i])); | |||
| } | |||
| }; | |||
| @@ -539,8 +532,8 @@ public: | |||
| // do check | |||
| for (size_t j = 0; j < SIMDRegister<type>::SIMDNumElements; ++j) | |||
| { | |||
| array_eq [j] = (array_a[j] == array_b[j]) ? static_cast<MaskType> (-1) : 0; | |||
| array_neq [j] = (array_a[j] != array_b[j]) ? static_cast<MaskType> (-1) : 0; | |||
| array_eq [j] = ( exactlyEqual (array_a[j], array_b[j])) ? static_cast<MaskType> (-1) : 0; | |||
| array_neq [j] = (! exactlyEqual (array_a[j], array_b[j])) ? static_cast<MaskType> (-1) : 0; | |||
| array_lt [j] = (array_a[j] < array_b[j]) ? static_cast<MaskType> (-1) : 0; | |||
| array_le [j] = (array_a[j] <= array_b[j]) ? static_cast<MaskType> (-1) : 0; | |||
| array_gt [j] = (array_a[j] > array_b[j]) ? static_cast<MaskType> (-1) : 0; | |||
| @@ -145,6 +145,11 @@ typename FIR::Coefficients<FloatType>::Ptr | |||
| auto* result = new typename FIR::Coefficients<FloatType> (static_cast<size_t> (N)); | |||
| auto* c = result->getRawCoefficients(); | |||
| auto sinc = [] (double x) | |||
| { | |||
| return approximatelyEqual (x, 0.0) ? 1 : std::sin (x * MathConstants<double>::pi) / (MathConstants<double>::pi * x); | |||
| }; | |||
| if (N % 2 == 1) | |||
| { | |||
| // Type I | |||
| @@ -153,9 +158,6 @@ typename FIR::Coefficients<FloatType>::Ptr | |||
| Matrix<double> b (M + 1, 1), | |||
| q (2 * M + 1, 1); | |||
| auto sinc = [] (double x) { return x == 0 ? 1 : std::sin (x * MathConstants<double>::pi) | |||
| / (MathConstants<double>::pi * x); }; | |||
| auto factorp = wp / MathConstants<double>::pi; | |||
| auto factors = ws / MathConstants<double>::pi; | |||
| @@ -191,9 +193,6 @@ typename FIR::Coefficients<FloatType>::Ptr | |||
| Matrix<double> qp (2 * M, 1); | |||
| Matrix<double> qs (2 * M, 1); | |||
| auto sinc = [] (double x) { return x == 0 ? 1 : std::sin (x * MathConstants<double>::pi) | |||
| / (MathConstants<double>::pi * x); }; | |||
| auto factorp = wp / MathConstants<double>::pi; | |||
| auto factors = ws / MathConstants<double>::pi; | |||
| @@ -647,7 +647,7 @@ static AudioBuffer<float> resampleImpulseResponse (const AudioBuffer<float>& buf | |||
| const double srcSampleRate, | |||
| const double destSampleRate) | |||
| { | |||
| if (srcSampleRate == destSampleRate) | |||
| if (approximatelyEqual (srcSampleRate, destSampleRate)) | |||
| return buf; | |||
| const auto factorReading = srcSampleRate / destSampleRate; | |||
| @@ -97,7 +97,7 @@ class ConvolutionTest : public UnitTest | |||
| expect (std::any_of (channel, channel + block.getNumSamples(), [] (float sample) | |||
| { | |||
| return sample != 0.0f; | |||
| return ! approximatelyEqual (sample, 0.0f); | |||
| })); | |||
| } | |||
| } | |||
| @@ -193,7 +193,7 @@ class ConvolutionTest : public UnitTest | |||
| processBlocksWithDiracImpulse(); | |||
| // Check if the impulse response was loaded | |||
| if (block.getSample (0, 1) != 0.0f) | |||
| if (! approximatelyEqual (block.getSample (0, 1), 0.0f)) | |||
| break; | |||
| } | |||
| } | |||
| @@ -108,7 +108,7 @@ public: | |||
| */ | |||
| void setTargetValue (FloatType newValue) noexcept | |||
| { | |||
| if (newValue == this->target) | |||
| if (approximatelyEqual (newValue, this->target)) | |||
| return; | |||
| if (stepsToTarget <= 0) | |||
| @@ -176,7 +176,7 @@ bool Matrix<ElementType>::solve (Matrix& b) const noexcept | |||
| { | |||
| auto denominator = A (0,0); | |||
| if (denominator == 0) | |||
| if (approximatelyEqual (denominator, (ElementType) 0)) | |||
| return false; | |||
| b (0, 0) /= denominator; | |||
| @@ -187,7 +187,7 @@ bool Matrix<ElementType>::solve (Matrix& b) const noexcept | |||
| { | |||
| auto denominator = A (0, 0) * A (1, 1) - A (0, 1) * A (1, 0); | |||
| if (denominator == 0) | |||
| if (approximatelyEqual (denominator, (ElementType) 0)) | |||
| return false; | |||
| auto factor = (1 / denominator); | |||
| @@ -204,7 +204,7 @@ bool Matrix<ElementType>::solve (Matrix& b) const noexcept | |||
| + A (0, 1) * (A (1, 2) * A (2, 0) - A (1, 0) * A (2, 2)) | |||
| + A (0, 2) * (A (1, 0) * A (2, 1) - A (1, 1) * A (2, 0)); | |||
| if (denominator == 0) | |||
| if (approximatelyEqual (denominator, (ElementType) 0)) | |||
| return false; | |||
| auto factor = 1 / denominator; | |||
| @@ -231,10 +231,10 @@ bool Matrix<ElementType>::solve (Matrix& b) const noexcept | |||
| for (size_t j = 0; j < n; ++j) | |||
| { | |||
| if (M (j, j) == 0) | |||
| if (approximatelyEqual (M (j, j), (ElementType) 0)) | |||
| { | |||
| auto i = j; | |||
| while (i < n && M (i, j) == 0) | |||
| while (i < n && approximatelyEqual (M (i, j), (ElementType) 0)) | |||
| ++i; | |||
| if (i == n) | |||
| @@ -271,7 +271,7 @@ private: | |||
| auto value1 = bufferData.getSample (channel, index1); | |||
| auto value2 = bufferData.getSample (channel, index2); | |||
| auto output = delayFrac == 0 ? value1 : value2 + alpha * (value1 - v[(size_t) channel]); | |||
| auto output = approximatelyEqual (delayFrac, (SampleType) 0) ? value1 : value2 + alpha * (value1 - v[(size_t) channel]); | |||
| v[(size_t) channel] = output; | |||
| return output; | |||
| @@ -39,8 +39,9 @@ Coefficients<NumericType>& Coefficients<NumericType>::assignImpl (const NumericT | |||
| static_assert (Num % 2 == 0, "Must supply an even number of coefficients"); | |||
| const auto a0Index = Num / 2; | |||
| const auto a0 = values[a0Index]; | |||
| const auto a0Inv = a0 != NumericType() ? static_cast<NumericType> (1) / values[a0Index] | |||
| : NumericType(); | |||
| const auto a0Inv = ! approximatelyEqual (a0, NumericType()) | |||
| ? static_cast<NumericType> (1) / values[a0Index] | |||
| : NumericType(); | |||
| coefficients.clearQuick(); | |||
| coefficients.ensureStorageAllocated ((int) jmax ((size_t) 8, Num)); | |||
| @@ -755,7 +755,7 @@ void Oversampling<SampleType>::updateDelayLine() | |||
| auto latency = getUncompensatedLatency(); | |||
| fractionalDelay = static_cast<SampleType> (1.0) - (latency - std::floor (latency)); | |||
| if (fractionalDelay == static_cast<SampleType> (1.0)) | |||
| if (approximatelyEqual (fractionalDelay, static_cast<SampleType> (1.0))) | |||
| fractionalDelay = static_cast<SampleType> (0.0); | |||
| else if (fractionalDelay < static_cast<SampleType> (0.618)) | |||
| fractionalDelay += static_cast<SampleType> (1.0); | |||
| @@ -48,9 +48,12 @@ struct ProcessSpec | |||
| constexpr bool operator== (const ProcessSpec& a, const ProcessSpec& b) | |||
| { | |||
| return a.sampleRate == b.sampleRate | |||
| && a.maximumBlockSize == b.maximumBlockSize | |||
| && a.numChannels == b.numChannels; | |||
| const auto tie = [] (const ProcessSpec& p) | |||
| { | |||
| return std::tie (p.sampleRate, p.maximumBlockSize, p.numChannels); | |||
| }; | |||
| return tie (a) == tie (b); | |||
| } | |||
| constexpr bool operator!= (const ProcessSpec& a, const ProcessSpec& b) { return ! (a == b); } | |||
| @@ -39,7 +39,7 @@ class ProcessorChainTest : public UnitTest | |||
| template <typename Context> | |||
| void process (const Context& context) noexcept | |||
| { | |||
| bufferWasClear = context.getInputBlock().getSample (0, 0) == 0; | |||
| bufferWasClear = approximatelyEqual (context.getInputBlock().getSample (0, 0), 0.0f); | |||
| if (! context.isBypassed) | |||
| context.getOutputBlock().add (AddValue); | |||