#pragma once template constexpr int numElementsInArray(Type (&)[N]) noexcept { return N; } /** Remaps a value from a source range to a target range. */ template auto jmap(Type sourceValue, Type sourceRangeMin, Type sourceRangeMax, Type targetRangeMin, Type targetRangeMax) -> Type { check(sourceRangeMax != sourceRangeMin); // mapping from a range of zero will produce NaN! return targetRangeMin + ((targetRangeMax - targetRangeMin) * (sourceValue - sourceRangeMin)) / (sourceRangeMax - sourceRangeMin); } template auto RoundToInt(const FloatType value) noexcept -> int { #ifdef __INTEL_COMPILER #pragma float_control (precise, on, push) #endif union { int asInt[2]; double asDouble; } n; n.asDouble = static_cast(value) + 6755399441055744.0; #if JUCE_BIG_ENDIAN return n.asInt [1]; #else return n.asInt[0]; #endif } /** Returns true if a value is at least zero, and also below a specified upper limit. This is basically a quicker way to write: @code valueToTest >= 0 && valueToTest < upperLimit @endcode */ template auto IsPositiveAndBelow(Type1 valueToTest, Type2 upperLimit) noexcept -> bool { check(Type1() <= static_cast (upperLimit)); // makes no sense to call this if the upper limit is itself below zero.. return Type1() <= valueToTest && valueToTest < static_cast(upperLimit); } template auto IsPositiveAndBelow(int valueToTest, Type upperLimit) noexcept -> bool { check(upperLimit >= 0); // makes no sense to call this if the upper limit is itself below zero.. return static_cast(valueToTest) < static_cast(upperLimit); }