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