upgrade to JUCE 5.4.3. Remove (probably) unused JUCE modules. Remove VST2 target (it's been end-of-life'd by Steinberg and by JUCE)
This commit is contained in:
		@ -39,10 +39,10 @@ class JUCE_API  AudioPlayHead
 | 
			
		||||
{
 | 
			
		||||
protected:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    AudioPlayHead() {}
 | 
			
		||||
    AudioPlayHead() = default;
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
    virtual ~AudioPlayHead() {}
 | 
			
		||||
    virtual ~AudioPlayHead() = default;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Frame rate types. */
 | 
			
		||||
 | 
			
		||||
@ -75,6 +75,27 @@ String AudioChannelSet::getChannelTypeName (AudioChannelSet::ChannelType type)
 | 
			
		||||
        case ambisonicZ:          return NEEDS_TRANS("Ambisonic Z");
 | 
			
		||||
        case topSideLeft:         return NEEDS_TRANS("Top Side Left");
 | 
			
		||||
        case topSideRight:        return NEEDS_TRANS("Top Side Right");
 | 
			
		||||
        case ambisonicACN4:       return NEEDS_TRANS("Ambisonic 4");
 | 
			
		||||
        case ambisonicACN5:       return NEEDS_TRANS("Ambisonic 5");
 | 
			
		||||
        case ambisonicACN6:       return NEEDS_TRANS("Ambisonic 6");
 | 
			
		||||
        case ambisonicACN7:       return NEEDS_TRANS("Ambisonic 7");
 | 
			
		||||
        case ambisonicACN8:       return NEEDS_TRANS("Ambisonic 8");
 | 
			
		||||
        case ambisonicACN9:       return NEEDS_TRANS("Ambisonic 9");
 | 
			
		||||
        case ambisonicACN10:      return NEEDS_TRANS("Ambisonic 10");
 | 
			
		||||
        case ambisonicACN11:      return NEEDS_TRANS("Ambisonic 11");
 | 
			
		||||
        case ambisonicACN12:      return NEEDS_TRANS("Ambisonic 12");
 | 
			
		||||
        case ambisonicACN13:      return NEEDS_TRANS("Ambisonic 13");
 | 
			
		||||
        case ambisonicACN14:      return NEEDS_TRANS("Ambisonic 14");
 | 
			
		||||
        case ambisonicACN15:      return NEEDS_TRANS("Ambisonic 15");
 | 
			
		||||
        case bottomFrontLeft:     return NEEDS_TRANS("Bottom Front Left");
 | 
			
		||||
        case bottomFrontCentre:   return NEEDS_TRANS("Bottom Front Centre");
 | 
			
		||||
        case bottomFrontRight:    return NEEDS_TRANS("Bottom Front Right");
 | 
			
		||||
        case bottomSideLeft:      return NEEDS_TRANS("Bottom Side Left");
 | 
			
		||||
        case bottomSideRight:     return NEEDS_TRANS("Bottom Side Right");
 | 
			
		||||
        case bottomRearLeft:      return NEEDS_TRANS("Bottom Rear Left");
 | 
			
		||||
        case bottomRearCentre:    return NEEDS_TRANS("Bottom Rear Centre");
 | 
			
		||||
        case bottomRearRight:     return NEEDS_TRANS("Bottom Rear Right");
 | 
			
		||||
        case discreteChannel0:    return NEEDS_TRANS("Discrete channel");
 | 
			
		||||
        default:                  break;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -115,8 +136,28 @@ String AudioChannelSet::getAbbreviatedChannelTypeName (AudioChannelSet::ChannelT
 | 
			
		||||
        case ambisonicACN1:       return "ACN1";
 | 
			
		||||
        case ambisonicACN2:       return "ACN2";
 | 
			
		||||
        case ambisonicACN3:       return "ACN3";
 | 
			
		||||
        case ambisonicACN4:       return "ACN4";
 | 
			
		||||
        case ambisonicACN5:       return "ACN5";
 | 
			
		||||
        case ambisonicACN6:       return "ACN6";
 | 
			
		||||
        case ambisonicACN7:       return "ACN7";
 | 
			
		||||
        case ambisonicACN8:       return "ACN8";
 | 
			
		||||
        case ambisonicACN9:       return "ACN9";
 | 
			
		||||
        case ambisonicACN10:      return "ACN10";
 | 
			
		||||
        case ambisonicACN11:      return "ACN11";
 | 
			
		||||
        case ambisonicACN12:      return "ACN12";
 | 
			
		||||
        case ambisonicACN13:      return "ACN13";
 | 
			
		||||
        case ambisonicACN14:      return "ACN14";
 | 
			
		||||
        case ambisonicACN15:      return "ACN15";
 | 
			
		||||
        case topSideLeft:         return "Tsl";
 | 
			
		||||
        case topSideRight:        return "Tsr";
 | 
			
		||||
        case bottomFrontLeft:     return "Bfl";
 | 
			
		||||
        case bottomFrontCentre:   return "Bfc";
 | 
			
		||||
        case bottomFrontRight:    return "Bfr";
 | 
			
		||||
        case bottomSideLeft:      return "Bsl";
 | 
			
		||||
        case bottomSideRight:     return "Bsr";
 | 
			
		||||
        case bottomRearLeft:      return "Brl";
 | 
			
		||||
        case bottomRearCentre:    return "Brc";
 | 
			
		||||
        case bottomRearRight:     return "Brr";
 | 
			
		||||
        default:                  break;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -130,38 +171,61 @@ AudioChannelSet::ChannelType AudioChannelSet::getChannelTypeFromAbbreviation (co
 | 
			
		||||
{
 | 
			
		||||
    if (abbr.length() > 0 && (abbr[0] >= '0' && abbr[0] <= '9'))
 | 
			
		||||
        return static_cast<AudioChannelSet::ChannelType> (static_cast<int> (discreteChannel0)
 | 
			
		||||
                                                               + abbr.getIntValue() + 1);
 | 
			
		||||
 | 
			
		||||
    if (abbr == "L")    return left;
 | 
			
		||||
    if (abbr == "R")    return right;
 | 
			
		||||
    if (abbr == "C")    return centre;
 | 
			
		||||
    if (abbr == "Lfe")  return LFE;
 | 
			
		||||
    if (abbr == "Ls")   return leftSurround;
 | 
			
		||||
    if (abbr == "Rs")   return rightSurround;
 | 
			
		||||
    if (abbr == "Lc")   return leftCentre;
 | 
			
		||||
    if (abbr == "Rc")   return rightCentre;
 | 
			
		||||
    if (abbr == "Cs")   return centreSurround;
 | 
			
		||||
    if (abbr == "Lrs")  return leftSurroundRear;
 | 
			
		||||
    if (abbr == "Rrs")  return rightSurroundRear;
 | 
			
		||||
    if (abbr == "Tm")   return topMiddle;
 | 
			
		||||
    if (abbr == "Tfl")  return topFrontLeft;
 | 
			
		||||
    if (abbr == "Tfc")  return topFrontCentre;
 | 
			
		||||
    if (abbr == "Tfr")  return topFrontRight;
 | 
			
		||||
    if (abbr == "Trl")  return topRearLeft;
 | 
			
		||||
    if (abbr == "Trc")  return topRearCentre;
 | 
			
		||||
    if (abbr == "Trr")  return topRearRight;
 | 
			
		||||
    if (abbr == "Wl")   return wideLeft;
 | 
			
		||||
    if (abbr == "Wr")   return wideRight;
 | 
			
		||||
    if (abbr == "Lfe2") return LFE2;
 | 
			
		||||
    if (abbr == "Lss")  return leftSurroundSide;
 | 
			
		||||
    if (abbr == "Rss")  return rightSurroundSide;
 | 
			
		||||
    if (abbr == "W")    return ambisonicW;
 | 
			
		||||
    if (abbr == "X")    return ambisonicX;
 | 
			
		||||
    if (abbr == "Y")    return ambisonicY;
 | 
			
		||||
    if (abbr == "Z")    return ambisonicZ;
 | 
			
		||||
    if (abbr == "Tsl")  return topSideLeft;
 | 
			
		||||
    if (abbr == "Tsr")  return topSideRight;
 | 
			
		||||
                                                               + abbr.getIntValue() - 1);
 | 
			
		||||
 | 
			
		||||
    if (abbr == "L")     return left;
 | 
			
		||||
    if (abbr == "R")     return right;
 | 
			
		||||
    if (abbr == "C")     return centre;
 | 
			
		||||
    if (abbr == "Lfe")   return LFE;
 | 
			
		||||
    if (abbr == "Ls")    return leftSurround;
 | 
			
		||||
    if (abbr == "Rs")    return rightSurround;
 | 
			
		||||
    if (abbr == "Lc")    return leftCentre;
 | 
			
		||||
    if (abbr == "Rc")    return rightCentre;
 | 
			
		||||
    if (abbr == "Cs")    return centreSurround;
 | 
			
		||||
    if (abbr == "Lrs")   return leftSurroundRear;
 | 
			
		||||
    if (abbr == "Rrs")   return rightSurroundRear;
 | 
			
		||||
    if (abbr == "Tm")    return topMiddle;
 | 
			
		||||
    if (abbr == "Tfl")   return topFrontLeft;
 | 
			
		||||
    if (abbr == "Tfc")   return topFrontCentre;
 | 
			
		||||
    if (abbr == "Tfr")   return topFrontRight;
 | 
			
		||||
    if (abbr == "Trl")   return topRearLeft;
 | 
			
		||||
    if (abbr == "Trc")   return topRearCentre;
 | 
			
		||||
    if (abbr == "Trr")   return topRearRight;
 | 
			
		||||
    if (abbr == "Wl")    return wideLeft;
 | 
			
		||||
    if (abbr == "Wr")    return wideRight;
 | 
			
		||||
    if (abbr == "Lfe2")  return LFE2;
 | 
			
		||||
    if (abbr == "Lss")   return leftSurroundSide;
 | 
			
		||||
    if (abbr == "Rss")   return rightSurroundSide;
 | 
			
		||||
    if (abbr == "W")     return ambisonicW;
 | 
			
		||||
    if (abbr == "X")     return ambisonicX;
 | 
			
		||||
    if (abbr == "Y")     return ambisonicY;
 | 
			
		||||
    if (abbr == "Z")     return ambisonicZ;
 | 
			
		||||
    if (abbr == "ACN0")  return ambisonicACN0;
 | 
			
		||||
    if (abbr == "ACN1")  return ambisonicACN1;
 | 
			
		||||
    if (abbr == "ACN2")  return ambisonicACN2;
 | 
			
		||||
    if (abbr == "ACN3")  return ambisonicACN3;
 | 
			
		||||
    if (abbr == "ACN4")  return ambisonicACN4;
 | 
			
		||||
    if (abbr == "ACN5")  return ambisonicACN5;
 | 
			
		||||
    if (abbr == "ACN6")  return ambisonicACN6;
 | 
			
		||||
    if (abbr == "ACN7")  return ambisonicACN7;
 | 
			
		||||
    if (abbr == "ACN8")  return ambisonicACN8;
 | 
			
		||||
    if (abbr == "ACN9")  return ambisonicACN9;
 | 
			
		||||
    if (abbr == "ACN10") return ambisonicACN10;
 | 
			
		||||
    if (abbr == "ACN11") return ambisonicACN11;
 | 
			
		||||
    if (abbr == "ACN12") return ambisonicACN12;
 | 
			
		||||
    if (abbr == "ACN13") return ambisonicACN13;
 | 
			
		||||
    if (abbr == "ACN14") return ambisonicACN14;
 | 
			
		||||
    if (abbr == "ACN15") return ambisonicACN15;
 | 
			
		||||
    if (abbr == "Tsl")   return topSideLeft;
 | 
			
		||||
    if (abbr == "Tsr")   return topSideRight;
 | 
			
		||||
    if (abbr == "Bfl")   return bottomFrontLeft;
 | 
			
		||||
    if (abbr == "Bfc")   return bottomFrontCentre;
 | 
			
		||||
    if (abbr == "Bfr")   return bottomFrontRight;
 | 
			
		||||
    if (abbr == "Bsl")   return bottomSideLeft;
 | 
			
		||||
    if (abbr == "Bsr")   return bottomSideRight;
 | 
			
		||||
    if (abbr == "Brl")   return bottomRearLeft;
 | 
			
		||||
    if (abbr == "Brc")   return bottomRearCentre;
 | 
			
		||||
    if (abbr == "Brr")   return bottomRearRight;
 | 
			
		||||
    return unknown;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -49,7 +49,7 @@ public:
 | 
			
		||||
    /** Creates an empty channel set.
 | 
			
		||||
        You can call addChannel to add channels to the set.
 | 
			
		||||
    */
 | 
			
		||||
    AudioChannelSet() noexcept  {}
 | 
			
		||||
    AudioChannelSet() = default;
 | 
			
		||||
 | 
			
		||||
    /** Creates a zero-channel set which can be used to indicate that a
 | 
			
		||||
        bus is disabled. */
 | 
			
		||||
@ -365,7 +365,21 @@ public:
 | 
			
		||||
        ambisonicZ          = ambisonicACN2, /**< Same as first-order ambisonic channel number 2. */
 | 
			
		||||
 | 
			
		||||
        //==============================================================================
 | 
			
		||||
        discreteChannel0    = 64  /**< Non-typed individual channels are indexed upwards from this value. */
 | 
			
		||||
        bottomFrontLeft     = 62, /**< Bottom Front Left (Bfl)   */
 | 
			
		||||
        bottomFrontCentre   = 63, /**< Bottom Front Centre (Bfc) */
 | 
			
		||||
        bottomFrontRight    = 64, /**< Bottom Front Right (Bfr)  */
 | 
			
		||||
 | 
			
		||||
        proxymityLeft       = 65, /**< Proximity Left (Pl)  */
 | 
			
		||||
        proximityRight      = 66, /**< Proximity Right (Pr) */
 | 
			
		||||
 | 
			
		||||
        bottomSideLeft      = 67, /**< Bottom Side Left (Bsl)   */
 | 
			
		||||
        bottomSideRight     = 68, /**< Bottom Side Right (Bsr)  */
 | 
			
		||||
        bottomRearLeft      = 69, /**< Bottom Rear Left (Brl)  */
 | 
			
		||||
        bottomRearCentre    = 70, /**< Bottom Rear Center (Brc)  */
 | 
			
		||||
        bottomRearRight     = 71, /**< Bottom Rear Right (Brr)  */
 | 
			
		||||
 | 
			
		||||
        //==============================================================================
 | 
			
		||||
        discreteChannel0    = 128  /**< Non-typed individual channels are indexed upwards from this value. */
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    /** Returns the name of a given channel type. For example, this method may return "Surround Left". */
 | 
			
		||||
 | 
			
		||||
@ -23,16 +23,16 @@
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
void AudioDataConverters::convertFloatToInt16LE (const float* source, void* dest, int numSamples, const int destBytesPerSample)
 | 
			
		||||
void AudioDataConverters::convertFloatToInt16LE (const float* source, void* dest, int numSamples, int destBytesPerSample)
 | 
			
		||||
{
 | 
			
		||||
    const double maxVal = (double) 0x7fff;
 | 
			
		||||
    char* intData = static_cast<char*> (dest);
 | 
			
		||||
    auto maxVal = (double) 0x7fff;
 | 
			
		||||
    auto intData = static_cast<char*> (dest);
 | 
			
		||||
 | 
			
		||||
    if (dest != (void*) source || destBytesPerSample <= 4)
 | 
			
		||||
    {
 | 
			
		||||
        for (int i = 0; i < numSamples; ++i)
 | 
			
		||||
        {
 | 
			
		||||
            *(uint16*) intData = ByteOrder::swapIfBigEndian ((uint16) (short) roundToInt (jlimit (-maxVal, maxVal, maxVal * source[i])));
 | 
			
		||||
            *reinterpret_cast<uint16*> (intData) = ByteOrder::swapIfBigEndian ((uint16) (short) roundToInt (jlimit (-maxVal, maxVal, maxVal * source[i])));
 | 
			
		||||
            intData += destBytesPerSample;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
@ -43,21 +43,21 @@ void AudioDataConverters::convertFloatToInt16LE (const float* source, void* dest
 | 
			
		||||
        for (int i = numSamples; --i >= 0;)
 | 
			
		||||
        {
 | 
			
		||||
            intData -= destBytesPerSample;
 | 
			
		||||
            *(uint16*) intData = ByteOrder::swapIfBigEndian ((uint16) (short) roundToInt (jlimit (-maxVal, maxVal, maxVal * source[i])));
 | 
			
		||||
            *reinterpret_cast<uint16*> (intData) = ByteOrder::swapIfBigEndian ((uint16) (short) roundToInt (jlimit (-maxVal, maxVal, maxVal * source[i])));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AudioDataConverters::convertFloatToInt16BE (const float* source, void* dest, int numSamples, const int destBytesPerSample)
 | 
			
		||||
void AudioDataConverters::convertFloatToInt16BE (const float* source, void* dest, int numSamples, int destBytesPerSample)
 | 
			
		||||
{
 | 
			
		||||
    const double maxVal = (double) 0x7fff;
 | 
			
		||||
    char* intData = static_cast<char*> (dest);
 | 
			
		||||
    auto maxVal = (double) 0x7fff;
 | 
			
		||||
    auto intData = static_cast<char*> (dest);
 | 
			
		||||
 | 
			
		||||
    if (dest != (void*) source || destBytesPerSample <= 4)
 | 
			
		||||
    {
 | 
			
		||||
        for (int i = 0; i < numSamples; ++i)
 | 
			
		||||
        {
 | 
			
		||||
            *(uint16*) intData = ByteOrder::swapIfLittleEndian ((uint16) (short) roundToInt (jlimit (-maxVal, maxVal, maxVal * source[i])));
 | 
			
		||||
            *reinterpret_cast<uint16*> (intData) = ByteOrder::swapIfLittleEndian ((uint16) (short) roundToInt (jlimit (-maxVal, maxVal, maxVal * source[i])));
 | 
			
		||||
            intData += destBytesPerSample;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
@ -68,15 +68,15 @@ void AudioDataConverters::convertFloatToInt16BE (const float* source, void* dest
 | 
			
		||||
        for (int i = numSamples; --i >= 0;)
 | 
			
		||||
        {
 | 
			
		||||
            intData -= destBytesPerSample;
 | 
			
		||||
            *(uint16*) intData = ByteOrder::swapIfLittleEndian ((uint16) (short) roundToInt (jlimit (-maxVal, maxVal, maxVal * source[i])));
 | 
			
		||||
            *reinterpret_cast<uint16*> (intData) = ByteOrder::swapIfLittleEndian ((uint16) (short) roundToInt (jlimit (-maxVal, maxVal, maxVal * source[i])));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AudioDataConverters::convertFloatToInt24LE (const float* source, void* dest, int numSamples, const int destBytesPerSample)
 | 
			
		||||
void AudioDataConverters::convertFloatToInt24LE (const float* source, void* dest, int numSamples, int destBytesPerSample)
 | 
			
		||||
{
 | 
			
		||||
    const double maxVal = (double) 0x7fffff;
 | 
			
		||||
    char* intData = static_cast<char*> (dest);
 | 
			
		||||
    auto maxVal = (double) 0x7fffff;
 | 
			
		||||
    auto intData = static_cast<char*> (dest);
 | 
			
		||||
 | 
			
		||||
    if (dest != (void*) source || destBytesPerSample <= 4)
 | 
			
		||||
    {
 | 
			
		||||
@ -98,10 +98,10 @@ void AudioDataConverters::convertFloatToInt24LE (const float* source, void* dest
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AudioDataConverters::convertFloatToInt24BE (const float* source, void* dest, int numSamples, const int destBytesPerSample)
 | 
			
		||||
void AudioDataConverters::convertFloatToInt24BE (const float* source, void* dest, int numSamples, int destBytesPerSample)
 | 
			
		||||
{
 | 
			
		||||
    const double maxVal = (double) 0x7fffff;
 | 
			
		||||
    char* intData = static_cast<char*> (dest);
 | 
			
		||||
    auto maxVal = (double) 0x7fffff;
 | 
			
		||||
    auto intData = static_cast<char*> (dest);
 | 
			
		||||
 | 
			
		||||
    if (dest != (void*) source || destBytesPerSample <= 4)
 | 
			
		||||
    {
 | 
			
		||||
@ -123,16 +123,16 @@ void AudioDataConverters::convertFloatToInt24BE (const float* source, void* dest
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AudioDataConverters::convertFloatToInt32LE (const float* source, void* dest, int numSamples, const int destBytesPerSample)
 | 
			
		||||
void AudioDataConverters::convertFloatToInt32LE (const float* source, void* dest, int numSamples, int destBytesPerSample)
 | 
			
		||||
{
 | 
			
		||||
    const double maxVal = (double) 0x7fffffff;
 | 
			
		||||
    char* intData = static_cast<char*> (dest);
 | 
			
		||||
    auto maxVal = (double) 0x7fffffff;
 | 
			
		||||
    auto intData = static_cast<char*> (dest);
 | 
			
		||||
 | 
			
		||||
    if (dest != (void*) source || destBytesPerSample <= 4)
 | 
			
		||||
    {
 | 
			
		||||
        for (int i = 0; i < numSamples; ++i)
 | 
			
		||||
        {
 | 
			
		||||
            *(uint32*)intData = ByteOrder::swapIfBigEndian ((uint32) roundToInt (jlimit (-maxVal, maxVal, maxVal * source[i])));
 | 
			
		||||
            *reinterpret_cast<uint32*> (intData) = ByteOrder::swapIfBigEndian ((uint32) roundToInt (jlimit (-maxVal, maxVal, maxVal * source[i])));
 | 
			
		||||
            intData += destBytesPerSample;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
@ -143,21 +143,21 @@ void AudioDataConverters::convertFloatToInt32LE (const float* source, void* dest
 | 
			
		||||
        for (int i = numSamples; --i >= 0;)
 | 
			
		||||
        {
 | 
			
		||||
            intData -= destBytesPerSample;
 | 
			
		||||
            *(uint32*)intData = ByteOrder::swapIfBigEndian ((uint32) roundToInt (jlimit (-maxVal, maxVal, maxVal * source[i])));
 | 
			
		||||
            *reinterpret_cast<uint32*> (intData) = ByteOrder::swapIfBigEndian ((uint32) roundToInt (jlimit (-maxVal, maxVal, maxVal * source[i])));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AudioDataConverters::convertFloatToInt32BE (const float* source, void* dest, int numSamples, const int destBytesPerSample)
 | 
			
		||||
void AudioDataConverters::convertFloatToInt32BE (const float* source, void* dest, int numSamples, int destBytesPerSample)
 | 
			
		||||
{
 | 
			
		||||
    const double maxVal = (double) 0x7fffffff;
 | 
			
		||||
    char* intData = static_cast<char*> (dest);
 | 
			
		||||
    auto maxVal = (double) 0x7fffffff;
 | 
			
		||||
    auto intData = static_cast<char*> (dest);
 | 
			
		||||
 | 
			
		||||
    if (dest != (void*) source || destBytesPerSample <= 4)
 | 
			
		||||
    {
 | 
			
		||||
        for (int i = 0; i < numSamples; ++i)
 | 
			
		||||
        {
 | 
			
		||||
            *(uint32*)intData = ByteOrder::swapIfLittleEndian ((uint32) roundToInt (jlimit (-maxVal, maxVal, maxVal * source[i])));
 | 
			
		||||
            *reinterpret_cast<uint32*> (intData) = ByteOrder::swapIfLittleEndian ((uint32) roundToInt (jlimit (-maxVal, maxVal, maxVal * source[i])));
 | 
			
		||||
            intData += destBytesPerSample;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
@ -168,12 +168,12 @@ void AudioDataConverters::convertFloatToInt32BE (const float* source, void* dest
 | 
			
		||||
        for (int i = numSamples; --i >= 0;)
 | 
			
		||||
        {
 | 
			
		||||
            intData -= destBytesPerSample;
 | 
			
		||||
            *(uint32*)intData = ByteOrder::swapIfLittleEndian ((uint32) roundToInt (jlimit (-maxVal, maxVal, maxVal * source[i])));
 | 
			
		||||
            *reinterpret_cast<uint32*> (intData) = ByteOrder::swapIfLittleEndian ((uint32) roundToInt (jlimit (-maxVal, maxVal, maxVal * source[i])));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AudioDataConverters::convertFloatToFloat32LE (const float* source, void* dest, int numSamples, const int destBytesPerSample)
 | 
			
		||||
void AudioDataConverters::convertFloatToFloat32LE (const float* source, void* dest, int numSamples, int destBytesPerSample)
 | 
			
		||||
{
 | 
			
		||||
    jassert (dest != (void*) source || destBytesPerSample <= 4); // This op can't be performed on in-place data!
 | 
			
		||||
 | 
			
		||||
@ -181,28 +181,28 @@ void AudioDataConverters::convertFloatToFloat32LE (const float* source, void* de
 | 
			
		||||
 | 
			
		||||
    for (int i = 0; i < numSamples; ++i)
 | 
			
		||||
    {
 | 
			
		||||
        *(float*) d = source[i];
 | 
			
		||||
        *reinterpret_cast<float*> (d) = source[i];
 | 
			
		||||
 | 
			
		||||
       #if JUCE_BIG_ENDIAN
 | 
			
		||||
        *(uint32*) d = ByteOrder::swap (*(uint32*) d);
 | 
			
		||||
        *reinterpret_cast<uint32*> (d) = ByteOrder::swap (*reinterpret_cast<uint32*> (d));
 | 
			
		||||
       #endif
 | 
			
		||||
 | 
			
		||||
        d += destBytesPerSample;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AudioDataConverters::convertFloatToFloat32BE (const float* source, void* dest, int numSamples, const int destBytesPerSample)
 | 
			
		||||
void AudioDataConverters::convertFloatToFloat32BE (const float* source, void* dest, int numSamples, int destBytesPerSample)
 | 
			
		||||
{
 | 
			
		||||
    jassert (dest != (void*) source || destBytesPerSample <= 4); // This op can't be performed on in-place data!
 | 
			
		||||
 | 
			
		||||
    char* d = static_cast<char*> (dest);
 | 
			
		||||
    auto d = static_cast<char*> (dest);
 | 
			
		||||
 | 
			
		||||
    for (int i = 0; i < numSamples; ++i)
 | 
			
		||||
    {
 | 
			
		||||
        *(float*) d = source[i];
 | 
			
		||||
        *reinterpret_cast<float*> (d) = source[i];
 | 
			
		||||
 | 
			
		||||
       #if JUCE_LITTLE_ENDIAN
 | 
			
		||||
        *(uint32*) d = ByteOrder::swap (*(uint32*) d);
 | 
			
		||||
        *reinterpret_cast<uint32*> (d) = ByteOrder::swap (*reinterpret_cast<uint32*> (d));
 | 
			
		||||
       #endif
 | 
			
		||||
 | 
			
		||||
        d += destBytesPerSample;
 | 
			
		||||
@ -210,16 +210,16 @@ void AudioDataConverters::convertFloatToFloat32BE (const float* source, void* de
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
void AudioDataConverters::convertInt16LEToFloat (const void* const source, float* const dest, int numSamples, const int srcBytesPerSample)
 | 
			
		||||
void AudioDataConverters::convertInt16LEToFloat (const void* source, float* dest, int numSamples, int srcBytesPerSample)
 | 
			
		||||
{
 | 
			
		||||
    const float scale = 1.0f / 0x7fff;
 | 
			
		||||
    const char* intData = static_cast<const char*> (source);
 | 
			
		||||
    auto intData = static_cast<const char*> (source);
 | 
			
		||||
 | 
			
		||||
    if (source != (void*) dest || srcBytesPerSample >= 4)
 | 
			
		||||
    {
 | 
			
		||||
        for (int i = 0; i < numSamples; ++i)
 | 
			
		||||
        {
 | 
			
		||||
            dest[i] = scale * (short) ByteOrder::swapIfBigEndian (*(uint16*)intData);
 | 
			
		||||
            dest[i] = scale * (short) ByteOrder::swapIfBigEndian (*reinterpret_cast<const uint16*> (intData));
 | 
			
		||||
            intData += srcBytesPerSample;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
@ -230,21 +230,21 @@ void AudioDataConverters::convertInt16LEToFloat (const void* const source, float
 | 
			
		||||
        for (int i = numSamples; --i >= 0;)
 | 
			
		||||
        {
 | 
			
		||||
            intData -= srcBytesPerSample;
 | 
			
		||||
            dest[i] = scale * (short) ByteOrder::swapIfBigEndian (*(uint16*)intData);
 | 
			
		||||
            dest[i] = scale * (short) ByteOrder::swapIfBigEndian (*reinterpret_cast<const uint16*> (intData));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AudioDataConverters::convertInt16BEToFloat (const void* const source, float* const dest, int numSamples, const int srcBytesPerSample)
 | 
			
		||||
void AudioDataConverters::convertInt16BEToFloat (const void* source, float* dest, int numSamples, int srcBytesPerSample)
 | 
			
		||||
{
 | 
			
		||||
    const float scale = 1.0f / 0x7fff;
 | 
			
		||||
    const char* intData = static_cast<const char*> (source);
 | 
			
		||||
    auto intData = static_cast<const char*> (source);
 | 
			
		||||
 | 
			
		||||
    if (source != (void*) dest || srcBytesPerSample >= 4)
 | 
			
		||||
    {
 | 
			
		||||
        for (int i = 0; i < numSamples; ++i)
 | 
			
		||||
        {
 | 
			
		||||
            dest[i] = scale * (short) ByteOrder::swapIfLittleEndian (*(uint16*)intData);
 | 
			
		||||
            dest[i] = scale * (short) ByteOrder::swapIfLittleEndian (*reinterpret_cast<const uint16*> (intData));
 | 
			
		||||
            intData += srcBytesPerSample;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
@ -255,15 +255,15 @@ void AudioDataConverters::convertInt16BEToFloat (const void* const source, float
 | 
			
		||||
        for (int i = numSamples; --i >= 0;)
 | 
			
		||||
        {
 | 
			
		||||
            intData -= srcBytesPerSample;
 | 
			
		||||
            dest[i] = scale * (short) ByteOrder::swapIfLittleEndian (*(uint16*)intData);
 | 
			
		||||
            dest[i] = scale * (short) ByteOrder::swapIfLittleEndian (*reinterpret_cast<const uint16*> (intData));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AudioDataConverters::convertInt24LEToFloat (const void* const source, float* const dest, int numSamples, const int srcBytesPerSample)
 | 
			
		||||
void AudioDataConverters::convertInt24LEToFloat (const void* source, float* dest, int numSamples, int srcBytesPerSample)
 | 
			
		||||
{
 | 
			
		||||
    const float scale = 1.0f / 0x7fffff;
 | 
			
		||||
    const char* intData = static_cast<const char*> (source);
 | 
			
		||||
    auto intData = static_cast<const char*> (source);
 | 
			
		||||
 | 
			
		||||
    if (source != (void*) dest || srcBytesPerSample >= 4)
 | 
			
		||||
    {
 | 
			
		||||
@ -285,10 +285,10 @@ void AudioDataConverters::convertInt24LEToFloat (const void* const source, float
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AudioDataConverters::convertInt24BEToFloat (const void* const source, float* const dest, int numSamples, const int srcBytesPerSample)
 | 
			
		||||
void AudioDataConverters::convertInt24BEToFloat (const void* source, float* dest, int numSamples, int srcBytesPerSample)
 | 
			
		||||
{
 | 
			
		||||
    const float scale = 1.0f / 0x7fffff;
 | 
			
		||||
    const char* intData = static_cast<const char*> (source);
 | 
			
		||||
    auto intData = static_cast<const char*> (source);
 | 
			
		||||
 | 
			
		||||
    if (source != (void*) dest || srcBytesPerSample >= 4)
 | 
			
		||||
    {
 | 
			
		||||
@ -310,16 +310,16 @@ void AudioDataConverters::convertInt24BEToFloat (const void* const source, float
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AudioDataConverters::convertInt32LEToFloat (const void* const source, float* const dest, int numSamples, const int srcBytesPerSample)
 | 
			
		||||
void AudioDataConverters::convertInt32LEToFloat (const void* source, float* dest, int numSamples, int srcBytesPerSample)
 | 
			
		||||
{
 | 
			
		||||
    const auto scale = 1.0f / (float) 0x7fffffff;
 | 
			
		||||
    const char* intData = static_cast<const char*> (source);
 | 
			
		||||
    const float scale = 1.0f / (float) 0x7fffffff;
 | 
			
		||||
    auto intData = static_cast<const char*> (source);
 | 
			
		||||
 | 
			
		||||
    if (source != (void*) dest || srcBytesPerSample >= 4)
 | 
			
		||||
    {
 | 
			
		||||
        for (int i = 0; i < numSamples; ++i)
 | 
			
		||||
        {
 | 
			
		||||
            dest[i] = scale * (int) ByteOrder::swapIfBigEndian (*(uint32*) intData);
 | 
			
		||||
            dest[i] = scale * (int) ByteOrder::swapIfBigEndian (*reinterpret_cast<const uint32*> (intData));
 | 
			
		||||
            intData += srcBytesPerSample;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
@ -330,21 +330,21 @@ void AudioDataConverters::convertInt32LEToFloat (const void* const source, float
 | 
			
		||||
        for (int i = numSamples; --i >= 0;)
 | 
			
		||||
        {
 | 
			
		||||
            intData -= srcBytesPerSample;
 | 
			
		||||
            dest[i] = scale * (int) ByteOrder::swapIfBigEndian (*(uint32*) intData);
 | 
			
		||||
            dest[i] = scale * (int) ByteOrder::swapIfBigEndian (*reinterpret_cast<const uint32*> (intData));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AudioDataConverters::convertInt32BEToFloat (const void* const source, float* const dest, int numSamples, const int srcBytesPerSample)
 | 
			
		||||
void AudioDataConverters::convertInt32BEToFloat (const void* source, float* dest, int numSamples, int srcBytesPerSample)
 | 
			
		||||
{
 | 
			
		||||
    const auto scale = 1.0f / (float) 0x7fffffff;
 | 
			
		||||
    const char* intData = static_cast<const char*> (source);
 | 
			
		||||
    const float scale = 1.0f / (float) 0x7fffffff;
 | 
			
		||||
    auto intData = static_cast<const char*> (source);
 | 
			
		||||
 | 
			
		||||
    if (source != (void*) dest || srcBytesPerSample >= 4)
 | 
			
		||||
    {
 | 
			
		||||
        for (int i = 0; i < numSamples; ++i)
 | 
			
		||||
        {
 | 
			
		||||
            dest[i] = scale * (int) ByteOrder::swapIfLittleEndian (*(uint32*) intData);
 | 
			
		||||
            dest[i] = scale * (int) ByteOrder::swapIfLittleEndian (*reinterpret_cast<const uint32*> (intData));
 | 
			
		||||
            intData += srcBytesPerSample;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
@ -355,21 +355,21 @@ void AudioDataConverters::convertInt32BEToFloat (const void* const source, float
 | 
			
		||||
        for (int i = numSamples; --i >= 0;)
 | 
			
		||||
        {
 | 
			
		||||
            intData -= srcBytesPerSample;
 | 
			
		||||
            dest[i] = scale * (int) ByteOrder::swapIfLittleEndian (*(uint32*) intData);
 | 
			
		||||
            dest[i] = scale * (int) ByteOrder::swapIfLittleEndian (*reinterpret_cast<const uint32*> (intData));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AudioDataConverters::convertFloat32LEToFloat (const void* const source, float* const dest, int numSamples, const int srcBytesPerSample)
 | 
			
		||||
void AudioDataConverters::convertFloat32LEToFloat (const void* source, float* dest, int numSamples, int srcBytesPerSample)
 | 
			
		||||
{
 | 
			
		||||
    const char* s = static_cast<const char*> (source);
 | 
			
		||||
    auto s = static_cast<const char*> (source);
 | 
			
		||||
 | 
			
		||||
    for (int i = 0; i < numSamples; ++i)
 | 
			
		||||
    {
 | 
			
		||||
        dest[i] = *(float*)s;
 | 
			
		||||
        dest[i] = *reinterpret_cast<const float*> (s);
 | 
			
		||||
 | 
			
		||||
       #if JUCE_BIG_ENDIAN
 | 
			
		||||
        uint32* const d = (uint32*) (dest + i);
 | 
			
		||||
        auto d = reinterpret_cast<uint32*> (dest + i);
 | 
			
		||||
        *d = ByteOrder::swap (*d);
 | 
			
		||||
       #endif
 | 
			
		||||
 | 
			
		||||
@ -377,16 +377,16 @@ void AudioDataConverters::convertFloat32LEToFloat (const void* const source, flo
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AudioDataConverters::convertFloat32BEToFloat (const void* const source, float* const dest, int numSamples, const int srcBytesPerSample)
 | 
			
		||||
void AudioDataConverters::convertFloat32BEToFloat (const void* source, float* dest, int numSamples, int srcBytesPerSample)
 | 
			
		||||
{
 | 
			
		||||
    const char* s = static_cast<const char*> (source);
 | 
			
		||||
    auto s = static_cast<const char*> (source);
 | 
			
		||||
 | 
			
		||||
    for (int i = 0; i < numSamples; ++i)
 | 
			
		||||
    {
 | 
			
		||||
        dest[i] = *(float*)s;
 | 
			
		||||
        dest[i] = *reinterpret_cast<const float*> (s);
 | 
			
		||||
 | 
			
		||||
       #if JUCE_LITTLE_ENDIAN
 | 
			
		||||
        uint32* const d = (uint32*) (dest + i);
 | 
			
		||||
        auto d = reinterpret_cast<uint32*> (dest + i);
 | 
			
		||||
        *d = ByteOrder::swap (*d);
 | 
			
		||||
       #endif
 | 
			
		||||
 | 
			
		||||
@ -396,10 +396,7 @@ void AudioDataConverters::convertFloat32BEToFloat (const void* const source, flo
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
void AudioDataConverters::convertFloatToFormat (const DataFormat destFormat,
 | 
			
		||||
                                                const float* const source,
 | 
			
		||||
                                                void* const dest,
 | 
			
		||||
                                                const int numSamples)
 | 
			
		||||
void AudioDataConverters::convertFloatToFormat (DataFormat destFormat, const float* source, void* dest, int numSamples)
 | 
			
		||||
{
 | 
			
		||||
    switch (destFormat)
 | 
			
		||||
    {
 | 
			
		||||
@ -415,10 +412,7 @@ void AudioDataConverters::convertFloatToFormat (const DataFormat destFormat,
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AudioDataConverters::convertFormatToFloat (const DataFormat sourceFormat,
 | 
			
		||||
                                                const void* const source,
 | 
			
		||||
                                                float* const dest,
 | 
			
		||||
                                                const int numSamples)
 | 
			
		||||
void AudioDataConverters::convertFormatToFloat (DataFormat sourceFormat, const void* source, float* dest, int numSamples)
 | 
			
		||||
{
 | 
			
		||||
    switch (sourceFormat)
 | 
			
		||||
    {
 | 
			
		||||
@ -435,15 +429,12 @@ void AudioDataConverters::convertFormatToFloat (const DataFormat sourceFormat,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
void AudioDataConverters::interleaveSamples (const float** const source,
 | 
			
		||||
                                             float* const dest,
 | 
			
		||||
                                             const int numSamples,
 | 
			
		||||
                                             const int numChannels)
 | 
			
		||||
void AudioDataConverters::interleaveSamples (const float** source, float* dest, int numSamples, int numChannels)
 | 
			
		||||
{
 | 
			
		||||
    for (int chan = 0; chan < numChannels; ++chan)
 | 
			
		||||
    {
 | 
			
		||||
        int i = chan;
 | 
			
		||||
        const float* src = source [chan];
 | 
			
		||||
        auto i = chan;
 | 
			
		||||
        auto src = source [chan];
 | 
			
		||||
 | 
			
		||||
        for (int j = 0; j < numSamples; ++j)
 | 
			
		||||
        {
 | 
			
		||||
@ -453,15 +444,12 @@ void AudioDataConverters::interleaveSamples (const float** const source,
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AudioDataConverters::deinterleaveSamples (const float* const source,
 | 
			
		||||
                                               float** const dest,
 | 
			
		||||
                                               const int numSamples,
 | 
			
		||||
                                               const int numChannels)
 | 
			
		||||
void AudioDataConverters::deinterleaveSamples (const float* source, float** dest, int numSamples, int numChannels)
 | 
			
		||||
{
 | 
			
		||||
    for (int chan = 0; chan < numChannels; ++chan)
 | 
			
		||||
    {
 | 
			
		||||
        int i = chan;
 | 
			
		||||
        float* dst = dest [chan];
 | 
			
		||||
        auto i = chan;
 | 
			
		||||
        auto dst = dest [chan];
 | 
			
		||||
 | 
			
		||||
        for (int j = 0; j < numSamples; ++j)
 | 
			
		||||
        {
 | 
			
		||||
@ -492,7 +480,7 @@ public:
 | 
			
		||||
        static void test (UnitTest& unitTest, bool inPlace, Random& r)
 | 
			
		||||
        {
 | 
			
		||||
            const int numSamples = 2048;
 | 
			
		||||
            int32 original [numSamples], converted [numSamples], reversed [numSamples];
 | 
			
		||||
            int32 original[numSamples], converted[numSamples], reversed[numSamples];
 | 
			
		||||
 | 
			
		||||
            {
 | 
			
		||||
                AudioData::Pointer<F1, E1, AudioData::NonInterleaved, AudioData::NonConst> d (original);
 | 
			
		||||
@ -514,13 +502,13 @@ public:
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // convert data from the source to dest format..
 | 
			
		||||
            std::unique_ptr<AudioData::Converter> conv (new AudioData::ConverterInstance <AudioData::Pointer<F1, E1, AudioData::NonInterleaved, AudioData::Const>,
 | 
			
		||||
                                                                                          AudioData::Pointer<F2, E2, AudioData::NonInterleaved, AudioData::NonConst>>());
 | 
			
		||||
            std::unique_ptr<AudioData::Converter> conv (new AudioData::ConverterInstance<AudioData::Pointer<F1, E1, AudioData::NonInterleaved, AudioData::Const>,
 | 
			
		||||
                                                                                         AudioData::Pointer<F2, E2, AudioData::NonInterleaved, AudioData::NonConst>>());
 | 
			
		||||
            conv->convertSamples (inPlace ? reversed : converted, original, numSamples);
 | 
			
		||||
 | 
			
		||||
            // ..and back again..
 | 
			
		||||
            conv.reset (new AudioData::ConverterInstance <AudioData::Pointer<F2, E2, AudioData::NonInterleaved, AudioData::Const>,
 | 
			
		||||
                                                          AudioData::Pointer<F1, E1, AudioData::NonInterleaved, AudioData::NonConst>>());
 | 
			
		||||
            conv.reset (new AudioData::ConverterInstance<AudioData::Pointer<F2, E2, AudioData::NonInterleaved, AudioData::Const>,
 | 
			
		||||
                                                         AudioData::Pointer<F1, E1, AudioData::NonInterleaved, AudioData::NonConst>>());
 | 
			
		||||
            if (! inPlace)
 | 
			
		||||
                zeromem (reversed, sizeof (reversed));
 | 
			
		||||
 | 
			
		||||
@ -582,7 +570,7 @@ public:
 | 
			
		||||
 | 
			
		||||
    void runTest() override
 | 
			
		||||
    {
 | 
			
		||||
        Random r = getRandom();
 | 
			
		||||
        auto r = getRandom();
 | 
			
		||||
        beginTest ("Round-trip conversion: Int8");
 | 
			
		||||
        Test1 <AudioData::Int8>::test (*this, r);
 | 
			
		||||
        beginTest ("Round-trip conversion: Int16");
 | 
			
		||||
 | 
			
		||||
@ -277,8 +277,8 @@ public:
 | 
			
		||||
    class NonInterleaved
 | 
			
		||||
    {
 | 
			
		||||
    public:
 | 
			
		||||
        inline NonInterleaved() noexcept {}
 | 
			
		||||
        inline NonInterleaved (const NonInterleaved&) noexcept {}
 | 
			
		||||
        inline NonInterleaved() = default;
 | 
			
		||||
        inline NonInterleaved (const NonInterleaved&) = default;
 | 
			
		||||
        inline NonInterleaved (const int) noexcept {}
 | 
			
		||||
        inline void copyFrom (const NonInterleaved&) noexcept {}
 | 
			
		||||
        template <class SampleFormatType> inline void advanceData (SampleFormatType& s) noexcept                    { s.advance(); }
 | 
			
		||||
@ -292,15 +292,15 @@ public:
 | 
			
		||||
    class Interleaved
 | 
			
		||||
    {
 | 
			
		||||
    public:
 | 
			
		||||
        inline Interleaved() noexcept : numInterleavedChannels (1) {}
 | 
			
		||||
        inline Interleaved (const Interleaved& other) noexcept : numInterleavedChannels (other.numInterleavedChannels) {}
 | 
			
		||||
        inline Interleaved() noexcept  {}
 | 
			
		||||
        inline Interleaved (const Interleaved& other) = default;
 | 
			
		||||
        inline Interleaved (const int numInterleavedChans) noexcept : numInterleavedChannels (numInterleavedChans) {}
 | 
			
		||||
        inline void copyFrom (const Interleaved& other) noexcept { numInterleavedChannels = other.numInterleavedChannels; }
 | 
			
		||||
        template <class SampleFormatType> inline void advanceData (SampleFormatType& s) noexcept                    { s.skip (numInterleavedChannels); }
 | 
			
		||||
        template <class SampleFormatType> inline void advanceDataBy (SampleFormatType& s, int numSamples) noexcept  { s.skip (numInterleavedChannels * numSamples); }
 | 
			
		||||
        template <class SampleFormatType> inline void clear (SampleFormatType& s, int numSamples) noexcept          { while (--numSamples >= 0) { s.clear(); s.skip (numInterleavedChannels); } }
 | 
			
		||||
        template <class SampleFormatType> inline int getNumBytesBetweenSamples (const SampleFormatType&) const noexcept { return numInterleavedChannels * SampleFormatType::bytesPerSample; }
 | 
			
		||||
        int numInterleavedChannels;
 | 
			
		||||
        int numInterleavedChannels = 1;
 | 
			
		||||
        enum { isInterleavedType = 1 };
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
@ -587,7 +587,7 @@ public:
 | 
			
		||||
    class Converter
 | 
			
		||||
    {
 | 
			
		||||
    public:
 | 
			
		||||
        virtual ~Converter() {}
 | 
			
		||||
        virtual ~Converter() = default;
 | 
			
		||||
 | 
			
		||||
        /** Converts a sequence of samples from the converter's source format into the dest format. */
 | 
			
		||||
        virtual void convertSamples (void* destSamples, const void* sourceSamples, int numSamples) const = 0;
 | 
			
		||||
 | 
			
		||||
@ -0,0 +1,79 @@
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2017 - ROLI Ltd.
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 5 End-User License
 | 
			
		||||
   Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
 | 
			
		||||
   27th April 2017).
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-5-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-5-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
AudioProcessLoadMeasurer::AudioProcessLoadMeasurer() {}
 | 
			
		||||
AudioProcessLoadMeasurer::~AudioProcessLoadMeasurer() {}
 | 
			
		||||
 | 
			
		||||
void AudioProcessLoadMeasurer::reset()
 | 
			
		||||
{
 | 
			
		||||
    reset (0, 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AudioProcessLoadMeasurer::reset (double sampleRate, int blockSize)
 | 
			
		||||
{
 | 
			
		||||
    cpuUsageMs = 0;
 | 
			
		||||
    xruns = 0;
 | 
			
		||||
 | 
			
		||||
    if (sampleRate > 0.0 && blockSize > 0)
 | 
			
		||||
    {
 | 
			
		||||
        msPerBlock = 1000.0 * blockSize / sampleRate;
 | 
			
		||||
        timeToCpuScale = (msPerBlock > 0.0) ? (1.0 / msPerBlock) : 0.0;
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        msPerBlock = 0;
 | 
			
		||||
        timeToCpuScale = 0;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AudioProcessLoadMeasurer::registerBlockRenderTime (double milliseconds)
 | 
			
		||||
{
 | 
			
		||||
    const double filterAmount = 0.2;
 | 
			
		||||
    cpuUsageMs += filterAmount * (milliseconds - cpuUsageMs);
 | 
			
		||||
 | 
			
		||||
    if (milliseconds > msPerBlock)
 | 
			
		||||
        ++xruns;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
double AudioProcessLoadMeasurer::getLoadAsProportion() const   { return jlimit (0.0, 1.0, timeToCpuScale * cpuUsageMs); }
 | 
			
		||||
double AudioProcessLoadMeasurer::getLoadAsPercentage() const   { return 100.0 * getLoadAsProportion(); }
 | 
			
		||||
 | 
			
		||||
int AudioProcessLoadMeasurer::getXRunCount() const             { return xruns; }
 | 
			
		||||
 | 
			
		||||
AudioProcessLoadMeasurer::ScopedTimer::ScopedTimer (AudioProcessLoadMeasurer& p)
 | 
			
		||||
   : owner (p), startTime (Time::getMillisecondCounterHiRes())
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
AudioProcessLoadMeasurer::ScopedTimer::~ScopedTimer()
 | 
			
		||||
{
 | 
			
		||||
    owner.registerBlockRenderTime (Time::getMillisecondCounterHiRes() - startTime);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
@ -0,0 +1,96 @@
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2017 - ROLI Ltd.
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 5 End-User License
 | 
			
		||||
   Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
 | 
			
		||||
   27th April 2017).
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-5-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-5-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
/**
 | 
			
		||||
    Maintains an ongoing measurement of the proportion of time which is being
 | 
			
		||||
    spent inside an audio callback.
 | 
			
		||||
*/
 | 
			
		||||
class JUCE_API  AudioProcessLoadMeasurer
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    /** */
 | 
			
		||||
    AudioProcessLoadMeasurer();
 | 
			
		||||
 | 
			
		||||
    /** Destructor. */
 | 
			
		||||
    ~AudioProcessLoadMeasurer();
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Resets the state. */
 | 
			
		||||
    void reset();
 | 
			
		||||
 | 
			
		||||
    /** Resets the counter, in preparation for use with the given sample rate and block size. */
 | 
			
		||||
    void reset (double sampleRate, int blockSize);
 | 
			
		||||
 | 
			
		||||
    /** Returns the current load as a proportion 0 to 1.0 */
 | 
			
		||||
    double getLoadAsProportion() const;
 | 
			
		||||
 | 
			
		||||
    /** Returns the current load as a percentage 0 to 100.0 */
 | 
			
		||||
    double getLoadAsPercentage() const;
 | 
			
		||||
 | 
			
		||||
    /** Returns the number of over- (or under-) runs recorded since the state was reset. */
 | 
			
		||||
    int getXRunCount() const;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** This class measures the time between its construction and destruction and
 | 
			
		||||
        adds it to an AudioProcessLoadMeasurer.
 | 
			
		||||
 | 
			
		||||
        e.g.
 | 
			
		||||
        @code
 | 
			
		||||
        {
 | 
			
		||||
            AudioProcessLoadMeasurer::ScopedTimer timer (myProcessLoadMeasurer);
 | 
			
		||||
            myCallback->doTheCallback();
 | 
			
		||||
        }
 | 
			
		||||
        @endcode
 | 
			
		||||
    */
 | 
			
		||||
    struct JUCE_API  ScopedTimer
 | 
			
		||||
    {
 | 
			
		||||
        ScopedTimer (AudioProcessLoadMeasurer&);
 | 
			
		||||
        ~ScopedTimer();
 | 
			
		||||
 | 
			
		||||
    private:
 | 
			
		||||
        AudioProcessLoadMeasurer& owner;
 | 
			
		||||
        double startTime;
 | 
			
		||||
 | 
			
		||||
        JUCE_DECLARE_NON_COPYABLE (ScopedTimer)
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    /** Can be called manually to add the time of a callback to the stats.
 | 
			
		||||
        Normally you probably would never call this - it's simpler and more robust to
 | 
			
		||||
        use a ScopedTimer to measure the time using an RAII pattern.
 | 
			
		||||
    */
 | 
			
		||||
    void registerBlockRenderTime (double millisecondsTaken);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    double cpuUsageMs = 0, timeToCpuScale = 0, msPerBlock = 0;
 | 
			
		||||
    int xruns = 0;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
@ -172,14 +172,14 @@ public:
 | 
			
		||||
    /** Destructor.
 | 
			
		||||
        This will free any memory allocated by the buffer.
 | 
			
		||||
    */
 | 
			
		||||
    ~AudioBuffer() noexcept {}
 | 
			
		||||
    ~AudioBuffer() = default;
 | 
			
		||||
 | 
			
		||||
    /** Move constructor */
 | 
			
		||||
    AudioBuffer (AudioBuffer&& other) noexcept
 | 
			
		||||
        : numChannels (other.numChannels),
 | 
			
		||||
          size (other.size),
 | 
			
		||||
          allocatedBytes (other.allocatedBytes),
 | 
			
		||||
          allocatedData (static_cast<HeapBlock<char, true>&&> (other.allocatedData)),
 | 
			
		||||
          allocatedData (std::move (other.allocatedData)),
 | 
			
		||||
          isClear (other.isClear)
 | 
			
		||||
    {
 | 
			
		||||
        if (numChannels < (int) numElementsInArray (preallocatedChannelSpace))
 | 
			
		||||
@ -205,7 +205,7 @@ public:
 | 
			
		||||
        numChannels = other.numChannels;
 | 
			
		||||
        size = other.size;
 | 
			
		||||
        allocatedBytes = other.allocatedBytes;
 | 
			
		||||
        allocatedData = static_cast<HeapBlock<char, true>&&> (other.allocatedData);
 | 
			
		||||
        allocatedData = std::move (other.allocatedData);
 | 
			
		||||
        isClear = other.isClear;
 | 
			
		||||
 | 
			
		||||
        if (numChannels < (int) numElementsInArray (preallocatedChannelSpace))
 | 
			
		||||
@ -1080,7 +1080,7 @@ private:
 | 
			
		||||
        allocatedBytes = (size_t) numChannels * (size_t) size * sizeof (Type) + channelListSize + 32;
 | 
			
		||||
        allocatedData.malloc (allocatedBytes);
 | 
			
		||||
        channels = reinterpret_cast<Type**> (allocatedData.get());
 | 
			
		||||
        auto* chan = (Type*) (allocatedData + channelListSize);
 | 
			
		||||
        auto chan = reinterpret_cast<Type*> (allocatedData + channelListSize);
 | 
			
		||||
 | 
			
		||||
        for (int i = 0; i < numChannels; ++i)
 | 
			
		||||
        {
 | 
			
		||||
 | 
			
		||||
@ -878,7 +878,7 @@ void JUCE_CALLTYPE FloatVectorOperations::convertFixedToFloat (float* dest, cons
 | 
			
		||||
                                  JUCE_LOAD_NONE, JUCE_INCREMENT_SRC_DEST, )
 | 
			
		||||
   #else
 | 
			
		||||
    JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] = (float) src[i] * multiplier,
 | 
			
		||||
                                  Mode::mul (mult, _mm_cvtepi32_ps (_mm_loadu_si128 ((const __m128i*) src))),
 | 
			
		||||
                                  Mode::mul (mult, _mm_cvtepi32_ps (_mm_loadu_si128 (reinterpret_cast<const __m128i*> (src)))),
 | 
			
		||||
                                  JUCE_LOAD_NONE, JUCE_INCREMENT_SRC_DEST,
 | 
			
		||||
                                  const Mode::ParallelType mult = Mode::load1 (multiplier);)
 | 
			
		||||
   #endif
 | 
			
		||||
 | 
			
		||||
@ -1,215 +0,0 @@
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2017 - ROLI Ltd.
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   The code included in this file is provided under the terms of the ISC license
 | 
			
		||||
   http://www.isc.org/downloads/software-support-policy/isc-license. Permission
 | 
			
		||||
   To use, copy, modify, and/or distribute this software for any purpose with or
 | 
			
		||||
   without fee is hereby granted provided that the above copyright notice and
 | 
			
		||||
   this permission notice appear in all copies.
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
/**
 | 
			
		||||
    Utility class for linearly smoothed values like volume etc. that should
 | 
			
		||||
    not change abruptly but as a linear ramp, to avoid audio glitches.
 | 
			
		||||
 | 
			
		||||
    @tags{Audio}
 | 
			
		||||
*/
 | 
			
		||||
template <typename FloatType>
 | 
			
		||||
class LinearSmoothedValue
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    /** Constructor. */
 | 
			
		||||
    LinearSmoothedValue() noexcept
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Constructor. */
 | 
			
		||||
    LinearSmoothedValue (FloatType initialValue) noexcept
 | 
			
		||||
        : currentValue (initialValue), target (initialValue)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Reset to a new sample rate and ramp length.
 | 
			
		||||
        @param sampleRate The sampling rate
 | 
			
		||||
        @param rampLengthInSeconds The duration of the ramp in seconds
 | 
			
		||||
    */
 | 
			
		||||
    void reset (double sampleRate, double rampLengthInSeconds) noexcept
 | 
			
		||||
    {
 | 
			
		||||
        jassert (sampleRate > 0 && rampLengthInSeconds >= 0);
 | 
			
		||||
        stepsToTarget = (int) std::floor (rampLengthInSeconds * sampleRate);
 | 
			
		||||
        currentValue = target;
 | 
			
		||||
        countdown = 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Set a new target value.
 | 
			
		||||
 | 
			
		||||
        @param newValue     The new target value
 | 
			
		||||
        @param force        If true, the value will be set immediately, bypassing the ramp
 | 
			
		||||
    */
 | 
			
		||||
    void setValue (FloatType newValue, bool force = false) noexcept
 | 
			
		||||
    {
 | 
			
		||||
        if (force)
 | 
			
		||||
        {
 | 
			
		||||
            target = currentValue = newValue;
 | 
			
		||||
            countdown = 0;
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (target != newValue)
 | 
			
		||||
        {
 | 
			
		||||
            target = newValue;
 | 
			
		||||
            countdown = stepsToTarget;
 | 
			
		||||
 | 
			
		||||
            if (countdown <= 0)
 | 
			
		||||
                currentValue = target;
 | 
			
		||||
            else
 | 
			
		||||
                step = (target - currentValue) / (FloatType) countdown;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Compute the next value.
 | 
			
		||||
        @returns Smoothed value
 | 
			
		||||
    */
 | 
			
		||||
    FloatType getNextValue() noexcept
 | 
			
		||||
    {
 | 
			
		||||
        if (countdown <= 0)
 | 
			
		||||
            return target;
 | 
			
		||||
 | 
			
		||||
        --countdown;
 | 
			
		||||
        currentValue += step;
 | 
			
		||||
        return currentValue;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Returns true if the current value is currently being interpolated. */
 | 
			
		||||
    bool isSmoothing() const noexcept
 | 
			
		||||
    {
 | 
			
		||||
        return countdown > 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Returns the target value towards which the smoothed value is currently moving. */
 | 
			
		||||
    FloatType getTargetValue() const noexcept
 | 
			
		||||
    {
 | 
			
		||||
        return target;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Applies a linear smoothed gain to a stream of samples
 | 
			
		||||
        S[i] *= gain
 | 
			
		||||
        @param samples Pointer to a raw array of samples
 | 
			
		||||
        @param numSamples Length of array of samples
 | 
			
		||||
    */
 | 
			
		||||
    void applyGain (FloatType* samples, int numSamples) noexcept
 | 
			
		||||
    {
 | 
			
		||||
        jassert(numSamples >= 0);
 | 
			
		||||
 | 
			
		||||
        if (isSmoothing())
 | 
			
		||||
        {
 | 
			
		||||
            for (int i = 0; i < numSamples; i++)
 | 
			
		||||
                samples[i] *= getNextValue();
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            FloatVectorOperations::multiply (samples, target, numSamples);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Computes output as linear smoothed gain applied to a stream of samples.
 | 
			
		||||
        Sout[i] = Sin[i] * gain
 | 
			
		||||
        @param samplesOut A pointer to a raw array of output samples
 | 
			
		||||
        @param samplesIn  A pointer to a raw array of input samples
 | 
			
		||||
        @param numSamples The length of the array of samples
 | 
			
		||||
    */
 | 
			
		||||
    void applyGain (FloatType* samplesOut, const FloatType* samplesIn, int numSamples) noexcept
 | 
			
		||||
    {
 | 
			
		||||
        jassert (numSamples >= 0);
 | 
			
		||||
 | 
			
		||||
        if (isSmoothing())
 | 
			
		||||
        {
 | 
			
		||||
            for (int i = 0; i < numSamples; i++)
 | 
			
		||||
                samplesOut[i] = samplesIn[i] * getNextValue();
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            FloatVectorOperations::multiply (samplesOut, samplesIn, target, numSamples);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Applies a linear smoothed gain to a buffer */
 | 
			
		||||
    void applyGain (AudioBuffer<FloatType>& buffer, int numSamples) noexcept
 | 
			
		||||
    {
 | 
			
		||||
        jassert (numSamples >= 0);
 | 
			
		||||
 | 
			
		||||
        if (isSmoothing())
 | 
			
		||||
        {
 | 
			
		||||
            if (buffer.getNumChannels() == 1)
 | 
			
		||||
            {
 | 
			
		||||
                FloatType* samples = buffer.getWritePointer(0);
 | 
			
		||||
 | 
			
		||||
                for (int i = 0; i < numSamples; i++)
 | 
			
		||||
                    samples[i] *= getNextValue();
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                for (int i = 0; i < numSamples; i++)
 | 
			
		||||
                {
 | 
			
		||||
                    const FloatType gain = getNextValue();
 | 
			
		||||
 | 
			
		||||
                    for (int channel = 0; channel < buffer.getNumChannels(); channel++)
 | 
			
		||||
                        buffer.setSample (channel, i, buffer.getSample (channel, i) * gain);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            buffer.applyGain (0, numSamples, target);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Skip the next numSamples samples.
 | 
			
		||||
 | 
			
		||||
        This is identical to calling getNextValue numSamples times.
 | 
			
		||||
        @see getNextValue
 | 
			
		||||
    */
 | 
			
		||||
    void skip (int numSamples) noexcept
 | 
			
		||||
    {
 | 
			
		||||
        if (numSamples >= countdown)
 | 
			
		||||
        {
 | 
			
		||||
            currentValue = target;
 | 
			
		||||
            countdown = 0;
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            currentValue += (step * static_cast<FloatType> (numSamples));
 | 
			
		||||
            countdown -= numSamples;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    FloatType currentValue = 0, target = 0, step = 0;
 | 
			
		||||
    int countdown = 0, stepsToTarget = 0;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
@ -56,9 +56,11 @@
 | 
			
		||||
#include "buffers/juce_AudioDataConverters.cpp"
 | 
			
		||||
#include "buffers/juce_FloatVectorOperations.cpp"
 | 
			
		||||
#include "buffers/juce_AudioChannelSet.cpp"
 | 
			
		||||
#include "effects/juce_IIRFilter.cpp"
 | 
			
		||||
#include "effects/juce_LagrangeInterpolator.cpp"
 | 
			
		||||
#include "effects/juce_CatmullRomInterpolator.cpp"
 | 
			
		||||
#include "buffers/juce_AudioProcessLoadMeasurer.cpp"
 | 
			
		||||
#include "utilities/juce_IIRFilter.cpp"
 | 
			
		||||
#include "utilities/juce_LagrangeInterpolator.cpp"
 | 
			
		||||
#include "utilities/juce_CatmullRomInterpolator.cpp"
 | 
			
		||||
#include "utilities/juce_SmoothedValue.cpp"
 | 
			
		||||
#include "midi/juce_MidiBuffer.cpp"
 | 
			
		||||
#include "midi/juce_MidiFile.cpp"
 | 
			
		||||
#include "midi/juce_MidiKeyboardState.cpp"
 | 
			
		||||
 | 
			
		||||
@ -31,7 +31,7 @@
 | 
			
		||||
 | 
			
		||||
  ID:               juce_audio_basics
 | 
			
		||||
  vendor:           juce
 | 
			
		||||
  version:          5.3.2
 | 
			
		||||
  version:          5.4.3
 | 
			
		||||
  name:             JUCE audio and MIDI data classes
 | 
			
		||||
  description:      Classes for audio buffer manipulation, midi message handling, synthesis, etc.
 | 
			
		||||
  website:          http://www.juce.com/juce
 | 
			
		||||
@ -84,12 +84,14 @@
 | 
			
		||||
#include "buffers/juce_FloatVectorOperations.h"
 | 
			
		||||
#include "buffers/juce_AudioSampleBuffer.h"
 | 
			
		||||
#include "buffers/juce_AudioChannelSet.h"
 | 
			
		||||
#include "effects/juce_Decibels.h"
 | 
			
		||||
#include "effects/juce_IIRFilter.h"
 | 
			
		||||
#include "effects/juce_LagrangeInterpolator.h"
 | 
			
		||||
#include "effects/juce_CatmullRomInterpolator.h"
 | 
			
		||||
#include "effects/juce_LinearSmoothedValue.h"
 | 
			
		||||
#include "effects/juce_Reverb.h"
 | 
			
		||||
#include "buffers/juce_AudioProcessLoadMeasurer.h"
 | 
			
		||||
#include "utilities/juce_Decibels.h"
 | 
			
		||||
#include "utilities/juce_IIRFilter.h"
 | 
			
		||||
#include "utilities/juce_LagrangeInterpolator.h"
 | 
			
		||||
#include "utilities/juce_CatmullRomInterpolator.h"
 | 
			
		||||
#include "utilities/juce_SmoothedValue.h"
 | 
			
		||||
#include "utilities/juce_Reverb.h"
 | 
			
		||||
#include "utilities/juce_ADSR.h"
 | 
			
		||||
#include "midi/juce_MidiMessage.h"
 | 
			
		||||
#include "midi/juce_MidiBuffer.h"
 | 
			
		||||
#include "midi/juce_MidiMessageSequence.h"
 | 
			
		||||
 | 
			
		||||
@ -57,9 +57,16 @@ namespace MidiBufferHelpers
 | 
			
		||||
        }
 | 
			
		||||
        else if (byte == 0xff)
 | 
			
		||||
        {
 | 
			
		||||
            int n;
 | 
			
		||||
            const int bytesLeft = MidiMessage::readVariableLengthVal (data + 1, n);
 | 
			
		||||
            size = jmin (maxBytes, n + 2 + bytesLeft);
 | 
			
		||||
            if (maxBytes == 1)
 | 
			
		||||
            {
 | 
			
		||||
                size = 1;
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                int n;
 | 
			
		||||
                const int bytesLeft = MidiMessage::readVariableLengthVal (data + 1, n);
 | 
			
		||||
                size = jmin (maxBytes, n + 2 + bytesLeft);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        else if (byte >= 0x80)
 | 
			
		||||
        {
 | 
			
		||||
 | 
			
		||||
@ -169,14 +169,14 @@ MidiFile& MidiFile::operator= (const MidiFile& other)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
MidiFile::MidiFile (MidiFile&& other)
 | 
			
		||||
    : tracks (static_cast<OwnedArray<MidiMessageSequence>&&> (other.tracks)),
 | 
			
		||||
    : tracks (std::move (other.tracks)),
 | 
			
		||||
      timeFormat (other.timeFormat)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
MidiFile& MidiFile::operator= (MidiFile&& other)
 | 
			
		||||
{
 | 
			
		||||
    tracks = static_cast<OwnedArray<MidiMessageSequence>&&> (other.tracks);
 | 
			
		||||
    tracks = std::move (other.tracks);
 | 
			
		||||
    timeFormat = other.timeFormat;
 | 
			
		||||
    return *this;
 | 
			
		||||
}
 | 
			
		||||
@ -245,7 +245,7 @@ double MidiFile::getLastTimestamp() const
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
bool MidiFile::readFrom (InputStream& sourceStream)
 | 
			
		||||
bool MidiFile::readFrom (InputStream& sourceStream, bool createMatchingNoteOffs)
 | 
			
		||||
{
 | 
			
		||||
    clear();
 | 
			
		||||
    MemoryBlock data;
 | 
			
		||||
@ -276,7 +276,7 @@ bool MidiFile::readFrom (InputStream& sourceStream)
 | 
			
		||||
                    break;
 | 
			
		||||
 | 
			
		||||
                if (chunkType == (int) ByteOrder::bigEndianInt ("MTrk"))
 | 
			
		||||
                    readNextTrack (d, chunkSize);
 | 
			
		||||
                    readNextTrack (d, chunkSize, createMatchingNoteOffs);
 | 
			
		||||
 | 
			
		||||
                size -= (size_t) chunkSize + 8;
 | 
			
		||||
                d += chunkSize;
 | 
			
		||||
@ -290,7 +290,7 @@ bool MidiFile::readFrom (InputStream& sourceStream)
 | 
			
		||||
    return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void MidiFile::readNextTrack (const uint8* data, int size)
 | 
			
		||||
void MidiFile::readNextTrack (const uint8* data, int size, bool createMatchingNoteOffs)
 | 
			
		||||
{
 | 
			
		||||
    double time = 0;
 | 
			
		||||
    uint8 lastStatusByte = 0;
 | 
			
		||||
@ -337,7 +337,9 @@ void MidiFile::readNextTrack (const uint8* data, int size)
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    addTrack (result);
 | 
			
		||||
    tracks.getLast()->updateMatchedPairs();
 | 
			
		||||
 | 
			
		||||
    if (createMatchingNoteOffs)
 | 
			
		||||
        tracks.getLast()->updateMatchedPairs();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
@ -361,7 +363,7 @@ void MidiFile::convertTimestampTicksToSeconds()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
bool MidiFile::writeTo (OutputStream& out, int midiFileType)
 | 
			
		||||
bool MidiFile::writeTo (OutputStream& out, int midiFileType) const
 | 
			
		||||
{
 | 
			
		||||
    jassert (midiFileType >= 0 && midiFileType <= 2);
 | 
			
		||||
 | 
			
		||||
@ -379,7 +381,7 @@ bool MidiFile::writeTo (OutputStream& out, int midiFileType)
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool MidiFile::writeTrack (OutputStream& mainOut, const MidiMessageSequence& ms)
 | 
			
		||||
bool MidiFile::writeTrack (OutputStream& mainOut, const MidiMessageSequence& ms) const
 | 
			
		||||
{
 | 
			
		||||
    MemoryOutputStream out;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -156,16 +156,25 @@ public:
 | 
			
		||||
        terms of midi ticks. To convert them to seconds, use the convertTimestampTicksToSeconds()
 | 
			
		||||
        method.
 | 
			
		||||
 | 
			
		||||
        @param sourceStream              the source stream
 | 
			
		||||
        @param createMatchingNoteOffs    if true, any missing note-offs for previous note-ons will
 | 
			
		||||
                                         be automatically added at the end of the file by calling
 | 
			
		||||
                                         MidiMessageSequence::updateMatchedPairs on each track.
 | 
			
		||||
 | 
			
		||||
        @returns true if the stream was read successfully
 | 
			
		||||
    */
 | 
			
		||||
    bool readFrom (InputStream& sourceStream);
 | 
			
		||||
    bool readFrom (InputStream& sourceStream, bool createMatchingNoteOffs = true);
 | 
			
		||||
 | 
			
		||||
    /** Writes the midi tracks as a standard midi file.
 | 
			
		||||
        The midiFileType value is written as the file's format type, which can be 0, 1
 | 
			
		||||
        or 2 - see the midi file spec for more info about that.
 | 
			
		||||
 | 
			
		||||
        @param destStream        the destination stream
 | 
			
		||||
        @param midiFileType      the type of midi file
 | 
			
		||||
 | 
			
		||||
        @returns true if the operation succeeded.
 | 
			
		||||
    */
 | 
			
		||||
    bool writeTo (OutputStream& destStream, int midiFileType = 1);
 | 
			
		||||
    bool writeTo (OutputStream& destStream, int midiFileType = 1) const;
 | 
			
		||||
 | 
			
		||||
    /** Converts the timestamp of all the midi events from midi ticks to seconds.
 | 
			
		||||
 | 
			
		||||
@ -174,14 +183,13 @@ public:
 | 
			
		||||
    */
 | 
			
		||||
    void convertTimestampTicksToSeconds();
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    OwnedArray<MidiMessageSequence> tracks;
 | 
			
		||||
    short timeFormat;
 | 
			
		||||
 | 
			
		||||
    void readNextTrack (const uint8*, int size);
 | 
			
		||||
    bool writeTrack (OutputStream&, const MidiMessageSequence&);
 | 
			
		||||
    void readNextTrack (const uint8*, int, bool);
 | 
			
		||||
    bool writeTrack (OutputStream&, const MidiMessageSequence&) const;
 | 
			
		||||
 | 
			
		||||
    JUCE_LEAK_DETECTOR (MidiFile)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -38,8 +38,8 @@ class JUCE_API  MidiKeyboardStateListener
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    MidiKeyboardStateListener() noexcept        {}
 | 
			
		||||
    virtual ~MidiKeyboardStateListener()        {}
 | 
			
		||||
    MidiKeyboardStateListener() = default;
 | 
			
		||||
    virtual ~MidiKeyboardStateListener() = default;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Called when one of the MidiKeyboardState's keys is pressed.
 | 
			
		||||
 | 
			
		||||
@ -224,9 +224,16 @@ MidiMessage::MidiMessage (const void* srcData, int sz, int& numBytesUsed, const
 | 
			
		||||
        }
 | 
			
		||||
        else if (byte == 0xff)
 | 
			
		||||
        {
 | 
			
		||||
            int n;
 | 
			
		||||
            const int bytesLeft = readVariableLengthVal (src + 1, n);
 | 
			
		||||
            size = jmin (sz + 1, n + 2 + bytesLeft);
 | 
			
		||||
            if (sz == 1)
 | 
			
		||||
            {
 | 
			
		||||
                size = 1;
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                int n;
 | 
			
		||||
                const int bytesLeft = readVariableLengthVal (src + 1, n);
 | 
			
		||||
                size = jmin (sz + 1, n + 2 + bytesLeft);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            auto dest = allocateSpace (size);
 | 
			
		||||
            *dest = (uint8) byte;
 | 
			
		||||
 | 
			
		||||
@ -83,19 +83,19 @@ public:
 | 
			
		||||
        complete message, and will return the number of bytes it used. This lets
 | 
			
		||||
        you read a sequence of midi messages from a file or stream.
 | 
			
		||||
 | 
			
		||||
        @param data             the data to read from
 | 
			
		||||
        @param maxBytesToUse    the maximum number of bytes it's allowed to read
 | 
			
		||||
        @param numBytesUsed     returns the number of bytes that were actually needed
 | 
			
		||||
        @param lastStatusByte   in a sequence of midi messages, the initial byte
 | 
			
		||||
                                can be dropped from a message if it's the same as the
 | 
			
		||||
                                first byte of the previous message, so this lets you
 | 
			
		||||
                                supply the byte to use if the first byte of the message
 | 
			
		||||
                                has in fact been dropped.
 | 
			
		||||
        @param timeStamp        the time to give the midi message - this value doesn't
 | 
			
		||||
                                use any particular units, so will be application-specific
 | 
			
		||||
        @param data                     the data to read from
 | 
			
		||||
        @param maxBytesToUse            the maximum number of bytes it's allowed to read
 | 
			
		||||
        @param numBytesUsed             returns the number of bytes that were actually needed
 | 
			
		||||
        @param lastStatusByte           in a sequence of midi messages, the initial byte
 | 
			
		||||
                                        can be dropped from a message if it's the same as the
 | 
			
		||||
                                        first byte of the previous message, so this lets you
 | 
			
		||||
                                        supply the byte to use if the first byte of the message
 | 
			
		||||
                                        has in fact been dropped.
 | 
			
		||||
        @param timeStamp                the time to give the midi message - this value doesn't
 | 
			
		||||
                                        use any particular units, so will be application-specific
 | 
			
		||||
        @param sysexHasEmbeddedLength   when reading sysexes, this flag indicates whether
 | 
			
		||||
                                to expect the data to begin with a variable-length field
 | 
			
		||||
                                indicating its size
 | 
			
		||||
                                        to expect the data to begin with a variable-length
 | 
			
		||||
                                        field indicating its size
 | 
			
		||||
    */
 | 
			
		||||
    MidiMessage (const void* data, int maxBytesToUse,
 | 
			
		||||
                 int& numBytesUsed, uint8 lastStatusByte,
 | 
			
		||||
 | 
			
		||||
@ -24,7 +24,7 @@ namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
MidiMessageSequence::MidiEventHolder::MidiEventHolder (const MidiMessage& mm) : message (mm) {}
 | 
			
		||||
MidiMessageSequence::MidiEventHolder::MidiEventHolder (MidiMessage&& mm) : message (static_cast<MidiMessage&&> (mm)) {}
 | 
			
		||||
MidiMessageSequence::MidiEventHolder::MidiEventHolder (MidiMessage&& mm) : message (std::move (mm)) {}
 | 
			
		||||
MidiMessageSequence::MidiEventHolder::~MidiEventHolder() {}
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
@ -53,13 +53,13 @@ MidiMessageSequence& MidiMessageSequence::operator= (const MidiMessageSequence&
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
MidiMessageSequence::MidiMessageSequence (MidiMessageSequence&& other) noexcept
 | 
			
		||||
    : list (static_cast<OwnedArray<MidiEventHolder>&&> (other.list))
 | 
			
		||||
    : list (std::move (other.list))
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
MidiMessageSequence& MidiMessageSequence::operator= (MidiMessageSequence&& other) noexcept
 | 
			
		||||
{
 | 
			
		||||
    list = static_cast<OwnedArray<MidiEventHolder>&&> (other.list);
 | 
			
		||||
    list = std::move (other.list);
 | 
			
		||||
    return *this;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -174,7 +174,7 @@ MidiMessageSequence::MidiEventHolder* MidiMessageSequence::addEvent (const MidiM
 | 
			
		||||
 | 
			
		||||
MidiMessageSequence::MidiEventHolder* MidiMessageSequence::addEvent (MidiMessage&& newMessage, double timeAdjustment)
 | 
			
		||||
{
 | 
			
		||||
    return addEvent (new MidiEventHolder (static_cast<MidiMessage&&> (newMessage)), timeAdjustment);
 | 
			
		||||
    return addEvent (new MidiEventHolder (std::move (newMessage)), timeAdjustment);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void MidiMessageSequence::deleteEvent (int index, bool deleteMatchingNoteUp)
 | 
			
		||||
 | 
			
		||||
@ -129,12 +129,12 @@ void MPEInstrument::setTimbreTrackingMode (TrackingMode modeToUse)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
void MPEInstrument::addListener (Listener* const listenerToAdd) noexcept
 | 
			
		||||
void MPEInstrument::addListener (Listener* listenerToAdd)
 | 
			
		||||
{
 | 
			
		||||
    listeners.add (listenerToAdd);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void MPEInstrument::removeListener (Listener* const listenerToRemove) noexcept
 | 
			
		||||
void MPEInstrument::removeListener (Listener* listenerToRemove)
 | 
			
		||||
{
 | 
			
		||||
    listeners.remove (listenerToRemove);
 | 
			
		||||
}
 | 
			
		||||
@ -156,7 +156,7 @@ void MPEInstrument::processNextMidiEvent (const MidiMessage& message)
 | 
			
		||||
//==============================================================================
 | 
			
		||||
void MPEInstrument::processMidiNoteOnMessage (const MidiMessage& message)
 | 
			
		||||
{
 | 
			
		||||
    // Note: if a note-on with velocity = 0 is used to convey a note-off,
 | 
			
		||||
    // Note: If a note-on with velocity = 0 is used to convey a note-off,
 | 
			
		||||
    // then the actual note-off velocity is not known. In this case,
 | 
			
		||||
    // the MPE convention is to use note-off velocity = 64.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -241,7 +241,7 @@ public:
 | 
			
		||||
    {
 | 
			
		||||
    public:
 | 
			
		||||
        /** Destructor. */
 | 
			
		||||
        virtual ~Listener() {}
 | 
			
		||||
        virtual ~Listener() = default;
 | 
			
		||||
 | 
			
		||||
        /** Implement this callback to be informed whenever a new expressive MIDI
 | 
			
		||||
            note is triggered.
 | 
			
		||||
@ -271,7 +271,7 @@ public:
 | 
			
		||||
            MPE note's key state (whether the key is down and/or the note is
 | 
			
		||||
            sustained) has changed.
 | 
			
		||||
 | 
			
		||||
            Note: if the key state changes to MPENote::off, noteReleased is
 | 
			
		||||
            Note: If the key state changes to MPENote::off, noteReleased is
 | 
			
		||||
            called instead.
 | 
			
		||||
        */
 | 
			
		||||
        virtual void noteKeyStateChanged (MPENote changedNote) = 0;
 | 
			
		||||
@ -286,10 +286,10 @@ public:
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Adds a listener. */
 | 
			
		||||
    void addListener (Listener* listenerToAdd) noexcept;
 | 
			
		||||
    void addListener (Listener* listenerToAdd);
 | 
			
		||||
 | 
			
		||||
    /** Removes a listener. */
 | 
			
		||||
    void removeListener (Listener* listenerToRemove) noexcept;
 | 
			
		||||
    void removeListener (Listener* listenerToRemove);
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Puts the instrument into legacy mode.
 | 
			
		||||
@ -352,8 +352,7 @@ private:
 | 
			
		||||
 | 
			
		||||
    struct MPEDimension
 | 
			
		||||
    {
 | 
			
		||||
        MPEDimension() noexcept  : trackingMode (lastNotePlayedOnChannel) {}
 | 
			
		||||
        TrackingMode trackingMode;
 | 
			
		||||
        TrackingMode trackingMode = lastNotePlayedOnChannel;
 | 
			
		||||
        MPEValue lastValueReceivedOnChannel[16];
 | 
			
		||||
        MPEValue MPENote::* value;
 | 
			
		||||
        MPEValue& getValue (MPENote& note) noexcept   { return note.*(value); }
 | 
			
		||||
 | 
			
		||||
@ -215,7 +215,7 @@ private:
 | 
			
		||||
        std::size_t pos = 0;
 | 
			
		||||
        MidiBuffer::Iterator iter (midiBuffer);
 | 
			
		||||
        MidiMessage midiMessage;
 | 
			
		||||
        int samplePosition; // Note: not actually used, so no need to initialise.
 | 
			
		||||
        int samplePosition; // Note: Not actually used, so no need to initialise.
 | 
			
		||||
 | 
			
		||||
        while (iter.getNextEvent (midiMessage, samplePosition))
 | 
			
		||||
        {
 | 
			
		||||
 | 
			
		||||
@ -35,7 +35,7 @@ namespace juce
 | 
			
		||||
    class instead. You just need to take care to send them to the appropriate
 | 
			
		||||
    per-note MIDI channel.
 | 
			
		||||
 | 
			
		||||
    Note: if you are working with an MPEZoneLayout object inside your app,
 | 
			
		||||
    Note: If you are working with an MPEZoneLayout object inside your app,
 | 
			
		||||
    you should not use the message sequences provided here. Instead, you should
 | 
			
		||||
    change the zone layout programmatically with the member functions provided in the
 | 
			
		||||
    MPEZoneLayout class itself. You should also make sure that the Expressive
 | 
			
		||||
 | 
			
		||||
@ -132,7 +132,7 @@ struct JUCE_API  MPENote
 | 
			
		||||
    */
 | 
			
		||||
    MPEValue pressure        { MPEValue::centreValue() };
 | 
			
		||||
 | 
			
		||||
    /** Inital value of timbre when the note was triggered.
 | 
			
		||||
    /** Initial value of timbre when the note was triggered.
 | 
			
		||||
        This should never change during the lifetime of an MPENote object.
 | 
			
		||||
    */
 | 
			
		||||
    MPEValue initialTimbre   { MPEValue::centreValue() };
 | 
			
		||||
 | 
			
		||||
@ -42,13 +42,16 @@ MPESynthesiser::~MPESynthesiser()
 | 
			
		||||
void MPESynthesiser::startVoice (MPESynthesiserVoice* voice, MPENote noteToStart)
 | 
			
		||||
{
 | 
			
		||||
    jassert (voice != nullptr);
 | 
			
		||||
 | 
			
		||||
    voice->currentlyPlayingNote = noteToStart;
 | 
			
		||||
    voice->noteOnTime = lastNoteOnCounter++;
 | 
			
		||||
    voice->noteStarted();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void MPESynthesiser::stopVoice (MPESynthesiserVoice* voice, MPENote noteToStop, bool allowTailOff)
 | 
			
		||||
{
 | 
			
		||||
    jassert (voice != nullptr);
 | 
			
		||||
 | 
			
		||||
    voice->currentlyPlayingNote = noteToStop;
 | 
			
		||||
    voice->noteStopped (allowTailOff);
 | 
			
		||||
}
 | 
			
		||||
@ -197,7 +200,7 @@ MPESynthesiserVoice* MPESynthesiser::findVoiceToSteal (MPENote noteToStealVoiceF
 | 
			
		||||
        // compilers generating code containing heap allocations..
 | 
			
		||||
        struct Sorter
 | 
			
		||||
        {
 | 
			
		||||
            bool operator() (const MPESynthesiserVoice* a, const MPESynthesiserVoice* b) const noexcept { return a->wasStartedBefore (*b); }
 | 
			
		||||
            bool operator() (const MPESynthesiserVoice* a, const MPESynthesiserVoice* b) const noexcept { return a->noteOnTime < b->noteOnTime; }
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        std::sort (usableVoices.begin(), usableVoices.end(), Sorter());
 | 
			
		||||
 | 
			
		||||
@ -72,7 +72,7 @@ public:
 | 
			
		||||
    MPESynthesiser (MPEInstrument* instrument);
 | 
			
		||||
 | 
			
		||||
    /** Destructor. */
 | 
			
		||||
    ~MPESynthesiser();
 | 
			
		||||
    ~MPESynthesiser() override;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Deletes all voices. */
 | 
			
		||||
@ -188,7 +188,7 @@ protected:
 | 
			
		||||
        renderNextBlock(). Do not call it yourself, otherwise the internal MPE note state
 | 
			
		||||
        will become inconsistent.
 | 
			
		||||
    */
 | 
			
		||||
    virtual void noteAdded (MPENote newNote) override;
 | 
			
		||||
    void noteAdded (MPENote newNote) override;
 | 
			
		||||
 | 
			
		||||
    /** Stops playing a note.
 | 
			
		||||
 | 
			
		||||
@ -203,7 +203,7 @@ protected:
 | 
			
		||||
        renderNextBlock(). Do not call it yourself, otherwise the internal MPE note state
 | 
			
		||||
        will become inconsistent.
 | 
			
		||||
    */
 | 
			
		||||
    virtual void noteReleased (MPENote finishedNote) override;
 | 
			
		||||
    void noteReleased (MPENote finishedNote) override;
 | 
			
		||||
 | 
			
		||||
    /** Will find any voice that is currently playing changedNote, update its
 | 
			
		||||
        currently playing note, and call its notePressureChanged method.
 | 
			
		||||
@ -211,7 +211,7 @@ protected:
 | 
			
		||||
        This method will be called automatically according to the midi data passed into
 | 
			
		||||
        renderNextBlock(). Do not call it yourself.
 | 
			
		||||
    */
 | 
			
		||||
    virtual void notePressureChanged (MPENote changedNote) override;
 | 
			
		||||
    void notePressureChanged (MPENote changedNote) override;
 | 
			
		||||
 | 
			
		||||
    /** Will find any voice that is currently playing changedNote, update its
 | 
			
		||||
        currently playing note, and call its notePitchbendChanged method.
 | 
			
		||||
@ -219,7 +219,7 @@ protected:
 | 
			
		||||
        This method will be called automatically according to the midi data passed into
 | 
			
		||||
        renderNextBlock(). Do not call it yourself.
 | 
			
		||||
    */
 | 
			
		||||
    virtual void notePitchbendChanged (MPENote changedNote) override;
 | 
			
		||||
    void notePitchbendChanged (MPENote changedNote) override;
 | 
			
		||||
 | 
			
		||||
    /** Will find any voice that is currently playing changedNote, update its
 | 
			
		||||
        currently playing note, and call its noteTimbreChanged method.
 | 
			
		||||
@ -227,7 +227,7 @@ protected:
 | 
			
		||||
        This method will be called automatically according to the midi data passed into
 | 
			
		||||
        renderNextBlock(). Do not call it yourself.
 | 
			
		||||
    */
 | 
			
		||||
    virtual void noteTimbreChanged (MPENote changedNote) override;
 | 
			
		||||
    void noteTimbreChanged (MPENote changedNote) override;
 | 
			
		||||
 | 
			
		||||
    /** Will find any voice that is currently playing changedNote, update its
 | 
			
		||||
        currently playing note, and call its noteKeyStateChanged method.
 | 
			
		||||
@ -235,24 +235,24 @@ protected:
 | 
			
		||||
        This method will be called automatically according to the midi data passed into
 | 
			
		||||
        renderNextBlock(). Do not call it yourself.
 | 
			
		||||
     */
 | 
			
		||||
    virtual void noteKeyStateChanged (MPENote changedNote) override;
 | 
			
		||||
    void noteKeyStateChanged (MPENote changedNote) override;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** This will simply call renderNextBlock for each currently active
 | 
			
		||||
        voice and fill the buffer with the sum.
 | 
			
		||||
        Override this method if you need to do more work to render your audio.
 | 
			
		||||
    */
 | 
			
		||||
    virtual void renderNextSubBlock (AudioBuffer<float>& outputAudio,
 | 
			
		||||
                                     int startSample,
 | 
			
		||||
                                     int numSamples) override;
 | 
			
		||||
    void renderNextSubBlock (AudioBuffer<float>& outputAudio,
 | 
			
		||||
                             int startSample,
 | 
			
		||||
                             int numSamples) override;
 | 
			
		||||
 | 
			
		||||
    /** This will simply call renderNextBlock for each currently active
 | 
			
		||||
        voice and fill the buffer with the sum. (souble-precision version)
 | 
			
		||||
        Override this method if you need to do more work to render your audio.
 | 
			
		||||
    */
 | 
			
		||||
    virtual void renderNextSubBlock (AudioBuffer<double>& outputAudio,
 | 
			
		||||
                                     int startSample,
 | 
			
		||||
                                     int numSamples) override;
 | 
			
		||||
    void renderNextSubBlock (AudioBuffer<double>& outputAudio,
 | 
			
		||||
                             int startSample,
 | 
			
		||||
                             int numSamples) override;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Searches through the voices to find one that's not currently playing, and
 | 
			
		||||
@ -304,6 +304,7 @@ protected:
 | 
			
		||||
private:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    bool shouldStealVoices = false;
 | 
			
		||||
    uint32 lastNoteOnCounter = 0;
 | 
			
		||||
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MPESynthesiser)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -42,11 +42,6 @@ bool MPESynthesiserVoice::isPlayingButReleased() const noexcept
 | 
			
		||||
    return isActive() && currentlyPlayingNote.keyState == MPENote::off;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool MPESynthesiserVoice::wasStartedBefore (const MPESynthesiserVoice& other) const noexcept
 | 
			
		||||
{
 | 
			
		||||
    return noteStartTime < other.noteStartTime;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void MPESynthesiserVoice::clearCurrentNote() noexcept
 | 
			
		||||
{
 | 
			
		||||
    currentlyPlayingNote = MPENote();
 | 
			
		||||
 | 
			
		||||
@ -156,8 +156,10 @@ public:
 | 
			
		||||
    */
 | 
			
		||||
    double getSampleRate() const noexcept                 { return currentSampleRate; }
 | 
			
		||||
 | 
			
		||||
    /** Returns true if this voice started playing its current note before the other voice did. */
 | 
			
		||||
    bool wasStartedBefore (const MPESynthesiserVoice& other) const noexcept;
 | 
			
		||||
    /** This will be set to an incrementing counter value in MPESynthesiser::startVoice()
 | 
			
		||||
        and can be used to determine the order in which voices started.
 | 
			
		||||
    */
 | 
			
		||||
    uint32 noteOnTime = 0;
 | 
			
		||||
 | 
			
		||||
protected:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
@ -182,7 +184,6 @@ protected:
 | 
			
		||||
private:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    friend class MPESynthesiser;
 | 
			
		||||
    uint32 noteStartTime = 0;
 | 
			
		||||
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MPESynthesiserVoice)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -80,13 +80,7 @@ public:
 | 
			
		||||
    */
 | 
			
		||||
    struct Zone
 | 
			
		||||
    {
 | 
			
		||||
        Zone (const Zone& other) noexcept
 | 
			
		||||
            : numMemberChannels (other.numMemberChannels),
 | 
			
		||||
              perNotePitchbendRange (other.perNotePitchbendRange),
 | 
			
		||||
              masterPitchbendRange (other.masterPitchbendRange),
 | 
			
		||||
              lowerZone (other.lowerZone)
 | 
			
		||||
        {
 | 
			
		||||
        }
 | 
			
		||||
        Zone (const Zone& other) = default;
 | 
			
		||||
 | 
			
		||||
        bool isLowerZone() const noexcept             { return lowerZone; }
 | 
			
		||||
        bool isUpperZone() const noexcept             { return ! lowerZone; }
 | 
			
		||||
@ -185,7 +179,7 @@ public:
 | 
			
		||||
    {
 | 
			
		||||
    public:
 | 
			
		||||
        /** Destructor. */
 | 
			
		||||
        virtual ~Listener() {}
 | 
			
		||||
        virtual ~Listener() = default;
 | 
			
		||||
 | 
			
		||||
        /** Implement this callback to be notified about any changes to this
 | 
			
		||||
            MPEZoneLayout. Will be called whenever a zone is added, zones are
 | 
			
		||||
 | 
			
		||||
@ -32,9 +32,7 @@ namespace juce
 | 
			
		||||
struct JUCE_API  AudioSourceChannelInfo
 | 
			
		||||
{
 | 
			
		||||
    /** Creates an uninitialised AudioSourceChannelInfo. */
 | 
			
		||||
    AudioSourceChannelInfo() noexcept
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
    AudioSourceChannelInfo() = default;
 | 
			
		||||
 | 
			
		||||
    /** Creates an AudioSourceChannelInfo. */
 | 
			
		||||
    AudioSourceChannelInfo (AudioBuffer<float>* bufferToUse,
 | 
			
		||||
@ -113,11 +111,11 @@ class JUCE_API  AudioSource
 | 
			
		||||
protected:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Creates an AudioSource. */
 | 
			
		||||
    AudioSource() noexcept      {}
 | 
			
		||||
    AudioSource() = default;
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
    /** Destructor. */
 | 
			
		||||
    virtual ~AudioSource()      {}
 | 
			
		||||
    virtual ~AudioSource()      = default;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Tells the source to prepare for playing.
 | 
			
		||||
 | 
			
		||||
@ -66,7 +66,7 @@ public:
 | 
			
		||||
        The input source may be deleted depending on whether the deleteSourceWhenDeleted
 | 
			
		||||
        flag was set in the constructor.
 | 
			
		||||
    */
 | 
			
		||||
    ~BufferingAudioSource();
 | 
			
		||||
    ~BufferingAudioSource() override;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Implementation of the AudioSource method. */
 | 
			
		||||
 | 
			
		||||
@ -56,7 +56,7 @@ public:
 | 
			
		||||
                                 bool deleteSourceWhenDeleted);
 | 
			
		||||
 | 
			
		||||
    /** Destructor. */
 | 
			
		||||
    ~ChannelRemappingAudioSource();
 | 
			
		||||
    ~ChannelRemappingAudioSource() override;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Specifies a number of channels that this audio source must produce from its
 | 
			
		||||
 | 
			
		||||
@ -43,7 +43,7 @@ public:
 | 
			
		||||
                          bool deleteInputWhenDeleted);
 | 
			
		||||
 | 
			
		||||
    /** Destructor. */
 | 
			
		||||
    ~IIRFilterAudioSource();
 | 
			
		||||
    ~IIRFilterAudioSource() override;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Changes the filter to use the same parameters as the one being passed in. */
 | 
			
		||||
 | 
			
		||||
@ -49,7 +49,8 @@ void MemoryAudioSource::getNextAudioBlock (const AudioSourceChannelInfo& bufferT
 | 
			
		||||
    auto max = 0, pos = 0;
 | 
			
		||||
    auto n = buffer.getNumSamples(), m = bufferToFill.numSamples;
 | 
			
		||||
 | 
			
		||||
    for (auto i = position; (i < n || isLooping) && (pos < m); i += max)
 | 
			
		||||
    int i;
 | 
			
		||||
    for (i = position; (i < n || isLooping) && (pos < m); i += max)
 | 
			
		||||
    {
 | 
			
		||||
        max = jmin (m - pos, n - (i % n));
 | 
			
		||||
 | 
			
		||||
@ -65,6 +66,8 @@ void MemoryAudioSource::getNextAudioBlock (const AudioSourceChannelInfo& bufferT
 | 
			
		||||
 | 
			
		||||
    if (pos < m)
 | 
			
		||||
        dst.clear (bufferToFill.startSample + pos, m - pos);
 | 
			
		||||
 | 
			
		||||
    position = (i % n);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
 | 
			
		||||
@ -41,7 +41,7 @@ public:
 | 
			
		||||
    MixerAudioSource();
 | 
			
		||||
 | 
			
		||||
    /** Destructor. */
 | 
			
		||||
    ~MixerAudioSource();
 | 
			
		||||
    ~MixerAudioSource() override;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Adds an input source to the mixer.
 | 
			
		||||
 | 
			
		||||
@ -40,11 +40,11 @@ class JUCE_API  PositionableAudioSource  : public AudioSource
 | 
			
		||||
protected:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Creates the PositionableAudioSource. */
 | 
			
		||||
    PositionableAudioSource() noexcept  {}
 | 
			
		||||
    PositionableAudioSource() = default;
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
    /** Destructor */
 | 
			
		||||
    ~PositionableAudioSource()          {}
 | 
			
		||||
    ~PositionableAudioSource() override = default;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Tells the stream to move to a new position.
 | 
			
		||||
 | 
			
		||||
@ -47,7 +47,7 @@ public:
 | 
			
		||||
                           int numChannels = 2);
 | 
			
		||||
 | 
			
		||||
    /** Destructor. */
 | 
			
		||||
    ~ResamplingAudioSource();
 | 
			
		||||
    ~ResamplingAudioSource() override;
 | 
			
		||||
 | 
			
		||||
    /** Changes the resampling ratio.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -44,7 +44,7 @@ public:
 | 
			
		||||
                       bool deleteInputWhenDeleted);
 | 
			
		||||
 | 
			
		||||
    /** Destructor. */
 | 
			
		||||
    ~ReverbAudioSource();
 | 
			
		||||
    ~ReverbAudioSource() override;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Returns the parameters from the reverb. */
 | 
			
		||||
 | 
			
		||||
@ -38,7 +38,7 @@ public:
 | 
			
		||||
    ToneGeneratorAudioSource();
 | 
			
		||||
 | 
			
		||||
    /** Destructor. */
 | 
			
		||||
    ~ToneGeneratorAudioSource();
 | 
			
		||||
    ~ToneGeneratorAudioSource() override;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Sets the signal's amplitude. */
 | 
			
		||||
 | 
			
		||||
@ -217,6 +217,18 @@ void Synthesiser::processNextBlock (AudioBuffer<floatType>& outputAudio,
 | 
			
		||||
template void Synthesiser::processNextBlock<float>  (AudioBuffer<float>&,  const MidiBuffer&, int, int);
 | 
			
		||||
template void Synthesiser::processNextBlock<double> (AudioBuffer<double>&, const MidiBuffer&, int, int);
 | 
			
		||||
 | 
			
		||||
void Synthesiser::renderNextBlock (AudioBuffer<float>& outputAudio, const MidiBuffer& inputMidi,
 | 
			
		||||
                                   int startSample, int numSamples)
 | 
			
		||||
{
 | 
			
		||||
    processNextBlock (outputAudio, inputMidi, startSample, numSamples);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Synthesiser::renderNextBlock (AudioBuffer<double>& outputAudio, const MidiBuffer& inputMidi,
 | 
			
		||||
                                   int startSample, int numSamples)
 | 
			
		||||
{
 | 
			
		||||
    processNextBlock (outputAudio, inputMidi, startSample, numSamples);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Synthesiser::renderVoices (AudioBuffer<float>& buffer, int startSample, int numSamples)
 | 
			
		||||
{
 | 
			
		||||
    for (auto* voice : voices)
 | 
			
		||||
@ -323,7 +335,7 @@ void Synthesiser::stopVoice (SynthesiserVoice* voice, float velocity, const bool
 | 
			
		||||
    voice->stopNote (velocity, allowTailOff);
 | 
			
		||||
 | 
			
		||||
    // the subclass MUST call clearCurrentNote() if it's not tailing off! RTFM for stopNote()!
 | 
			
		||||
    jassert (allowTailOff || (voice->getCurrentlyPlayingNote() < 0 && voice->getCurrentlyPlayingSound() == 0));
 | 
			
		||||
    jassert (allowTailOff || (voice->getCurrentlyPlayingNote() < 0 && voice->getCurrentlyPlayingSound() == nullptr));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Synthesiser::noteOff (const int midiChannel,
 | 
			
		||||
@ -338,7 +350,7 @@ void Synthesiser::noteOff (const int midiChannel,
 | 
			
		||||
        if (voice->getCurrentlyPlayingNote() == midiNoteNumber
 | 
			
		||||
              && voice->isPlayingChannel (midiChannel))
 | 
			
		||||
        {
 | 
			
		||||
            if (SynthesiserSound* const sound = voice->getCurrentlyPlayingSound())
 | 
			
		||||
            if (auto sound = voice->getCurrentlyPlayingSound())
 | 
			
		||||
            {
 | 
			
		||||
                if (sound->appliesToNote (midiNoteNumber)
 | 
			
		||||
                     && sound->appliesToChannel (midiChannel))
 | 
			
		||||
 | 
			
		||||
@ -46,7 +46,7 @@ protected:
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
    /** Destructor. */
 | 
			
		||||
    virtual ~SynthesiserSound();
 | 
			
		||||
    ~SynthesiserSound() override;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Returns true if this sound should be played when a given midi note is pressed.
 | 
			
		||||
@ -352,7 +352,7 @@ public:
 | 
			
		||||
    int getNumSounds() const noexcept                               { return sounds.size(); }
 | 
			
		||||
 | 
			
		||||
    /** Returns one of the sounds. */
 | 
			
		||||
    SynthesiserSound* getSound (int index) const noexcept           { return sounds [index]; }
 | 
			
		||||
    SynthesiserSound::Ptr getSound (int index) const noexcept       { return sounds[index]; }
 | 
			
		||||
 | 
			
		||||
    /** Adds a new sound to the synthesiser.
 | 
			
		||||
 | 
			
		||||
@ -525,21 +525,15 @@ public:
 | 
			
		||||
        both to the audio output buffer and the midi input buffer, so any midi events
 | 
			
		||||
        with timestamps outside the specified region will be ignored.
 | 
			
		||||
    */
 | 
			
		||||
    inline void renderNextBlock (AudioBuffer<float>& outputAudio,
 | 
			
		||||
                                 const MidiBuffer& inputMidi,
 | 
			
		||||
                                 int startSample,
 | 
			
		||||
                                 int numSamples)
 | 
			
		||||
    {
 | 
			
		||||
        processNextBlock (outputAudio, inputMidi, startSample, numSamples);
 | 
			
		||||
    }
 | 
			
		||||
    void renderNextBlock (AudioBuffer<float>& outputAudio,
 | 
			
		||||
                          const MidiBuffer& inputMidi,
 | 
			
		||||
                          int startSample,
 | 
			
		||||
                          int numSamples);
 | 
			
		||||
 | 
			
		||||
    inline void renderNextBlock (AudioBuffer<double>& outputAudio,
 | 
			
		||||
                                 const MidiBuffer& inputMidi,
 | 
			
		||||
                                 int startSample,
 | 
			
		||||
                                 int numSamples)
 | 
			
		||||
    {
 | 
			
		||||
        processNextBlock (outputAudio, inputMidi, startSample, numSamples);
 | 
			
		||||
    }
 | 
			
		||||
    void renderNextBlock (AudioBuffer<double>& outputAudio,
 | 
			
		||||
                          const MidiBuffer& inputMidi,
 | 
			
		||||
                          int startSample,
 | 
			
		||||
                          int numSamples);
 | 
			
		||||
 | 
			
		||||
    /** Returns the current target sample rate at which rendering is being done.
 | 
			
		||||
        Subclasses may need to know this so that they can pitch things correctly.
 | 
			
		||||
@ -632,12 +626,6 @@ protected:
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    template <typename floatType>
 | 
			
		||||
    void processNextBlock (AudioBuffer<floatType>& outputAudio,
 | 
			
		||||
                           const MidiBuffer& inputMidi,
 | 
			
		||||
                           int startSample,
 | 
			
		||||
                           int numSamples);
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    double sampleRate = 0;
 | 
			
		||||
    uint32 lastNoteOnCounter = 0;
 | 
			
		||||
    int minimumSubBlockSize = 32;
 | 
			
		||||
@ -645,6 +633,9 @@ private:
 | 
			
		||||
    bool shouldStealNotes = true;
 | 
			
		||||
    BigInteger sustainPedalsDown;
 | 
			
		||||
 | 
			
		||||
    template <typename floatType>
 | 
			
		||||
    void processNextBlock (AudioBuffer<floatType>&, const MidiBuffer&, int startSample, int numSamples);
 | 
			
		||||
 | 
			
		||||
   #if JUCE_CATCH_DEPRECATED_CODE_MISUSE
 | 
			
		||||
    // Note the new parameters for these methods.
 | 
			
		||||
    virtual int findFreeVoice (const bool) const { return 0; }
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										255
									
								
								modules/juce_audio_basics/utilities/juce_ADSR.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										255
									
								
								modules/juce_audio_basics/utilities/juce_ADSR.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,255 @@
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2017 - ROLI Ltd.
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   The code included in this file is provided under the terms of the ISC license
 | 
			
		||||
   http://www.isc.org/downloads/software-support-policy/isc-license. Permission
 | 
			
		||||
   To use, copy, modify, and/or distribute this software for any purpose with or
 | 
			
		||||
   without fee is hereby granted provided that the above copyright notice and
 | 
			
		||||
   this permission notice appear in all copies.
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
/**
 | 
			
		||||
    A very simple ADSR envelope class.
 | 
			
		||||
 | 
			
		||||
    To use it, call setSampleRate() with the current sample rate and give it some parameters
 | 
			
		||||
    with setParameters() then call getNextSample() to get the envelope value to be applied
 | 
			
		||||
    to each audio sample or applyEnvelopeToBuffer() to apply the envelope to a whole buffer.
 | 
			
		||||
*/
 | 
			
		||||
class ADSR
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    ADSR()
 | 
			
		||||
    {
 | 
			
		||||
        setSampleRate (44100.0);
 | 
			
		||||
        setParameters ({});
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Holds the parameters being used by an ADSR object. */
 | 
			
		||||
    struct Parameters
 | 
			
		||||
    {
 | 
			
		||||
        /** Attack time in seconds. */
 | 
			
		||||
        float attack  = 0.1f;
 | 
			
		||||
 | 
			
		||||
        /** Decay time in seconds. */
 | 
			
		||||
        float decay   = 0.1f;
 | 
			
		||||
 | 
			
		||||
        /** Sustain level. */
 | 
			
		||||
        float sustain = 1.0f;
 | 
			
		||||
 | 
			
		||||
        /** Release time in seconds. */
 | 
			
		||||
        float release = 0.1f;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    /** Sets the parameters that will be used by an ADSR object.
 | 
			
		||||
 | 
			
		||||
        You must have called setSampleRate() with the correct sample rate before
 | 
			
		||||
        this otherwise the values may be incorrect!
 | 
			
		||||
 | 
			
		||||
        @see getParameters
 | 
			
		||||
    */
 | 
			
		||||
    void setParameters (const Parameters& newParameters)
 | 
			
		||||
    {
 | 
			
		||||
        currentParameters = newParameters;
 | 
			
		||||
 | 
			
		||||
        sustainLevel = newParameters.sustain;
 | 
			
		||||
        calculateRates (newParameters);
 | 
			
		||||
 | 
			
		||||
        if (currentState != State::idle)
 | 
			
		||||
            checkCurrentState();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Returns the parameters currently being used by an ADSR object.
 | 
			
		||||
 | 
			
		||||
        @see setParameters
 | 
			
		||||
    */
 | 
			
		||||
    const Parameters& getParameters() const    { return currentParameters; }
 | 
			
		||||
 | 
			
		||||
    /** Returns true if the envelope is in its attack, decay, sustain or release stage. */
 | 
			
		||||
    bool isActive() const noexcept             { return currentState != State::idle; }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Sets the sample rate that will be used for the envelope.
 | 
			
		||||
 | 
			
		||||
        This must be called before the getNextSample() or setParameters() methods.
 | 
			
		||||
    */
 | 
			
		||||
    void setSampleRate (double sampleRate)
 | 
			
		||||
    {
 | 
			
		||||
        jassert (sampleRate > 0.0);
 | 
			
		||||
        sr = sampleRate;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Resets the envelope to an idle state. */
 | 
			
		||||
    void reset()
 | 
			
		||||
    {
 | 
			
		||||
        envelopeVal = 0.0f;
 | 
			
		||||
        currentState = State::idle;
 | 
			
		||||
 | 
			
		||||
        if (resetReleaseRate)
 | 
			
		||||
        {
 | 
			
		||||
            releaseRate = static_cast<float> (sustainLevel / (currentParameters.release * sr));
 | 
			
		||||
            resetReleaseRate = false;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Starts the attack phase of the envelope. */
 | 
			
		||||
    void noteOn()
 | 
			
		||||
    {
 | 
			
		||||
        if (attackRate > 0.0f)
 | 
			
		||||
        {
 | 
			
		||||
            currentState = State::attack;
 | 
			
		||||
        }
 | 
			
		||||
        else if (decayRate > 0.0f)
 | 
			
		||||
        {
 | 
			
		||||
            envelopeVal = 1.0f;
 | 
			
		||||
            currentState = State::decay;
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            currentState = State::sustain;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Starts the release phase of the envelope. */
 | 
			
		||||
    void noteOff()
 | 
			
		||||
    {
 | 
			
		||||
        if (currentState != State::idle)
 | 
			
		||||
        {
 | 
			
		||||
            if (releaseRate > 0.0f)
 | 
			
		||||
            {
 | 
			
		||||
                if (currentState != State::sustain)
 | 
			
		||||
                {
 | 
			
		||||
                    releaseRate = static_cast<float> (envelopeVal / (currentParameters.release * sr));
 | 
			
		||||
                    resetReleaseRate = true;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                currentState = State::release;
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                reset();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Returns the next sample value for an ADSR object.
 | 
			
		||||
 | 
			
		||||
        @see applyEnvelopeToBuffer
 | 
			
		||||
    */
 | 
			
		||||
    float getNextSample()
 | 
			
		||||
    {
 | 
			
		||||
        if (currentState == State::idle)
 | 
			
		||||
            return 0.0f;
 | 
			
		||||
 | 
			
		||||
        if (currentState == State::attack)
 | 
			
		||||
        {
 | 
			
		||||
            envelopeVal += attackRate;
 | 
			
		||||
 | 
			
		||||
            if (envelopeVal >= 1.0f)
 | 
			
		||||
            {
 | 
			
		||||
                envelopeVal = 1.0f;
 | 
			
		||||
 | 
			
		||||
                if (decayRate > 0.0f)
 | 
			
		||||
                    currentState = State::decay;
 | 
			
		||||
                else
 | 
			
		||||
                    currentState = State::sustain;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        else if (currentState == State::decay)
 | 
			
		||||
        {
 | 
			
		||||
            envelopeVal -= decayRate;
 | 
			
		||||
 | 
			
		||||
            if (envelopeVal <= sustainLevel)
 | 
			
		||||
            {
 | 
			
		||||
                envelopeVal = sustainLevel;
 | 
			
		||||
                currentState = State::sustain;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        else if (currentState == State::sustain)
 | 
			
		||||
        {
 | 
			
		||||
            envelopeVal = sustainLevel;
 | 
			
		||||
        }
 | 
			
		||||
        else if (currentState == State::release)
 | 
			
		||||
        {
 | 
			
		||||
            envelopeVal -= releaseRate;
 | 
			
		||||
 | 
			
		||||
            if (envelopeVal <= 0.0f)
 | 
			
		||||
                reset();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return envelopeVal;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** This method will conveniently apply the next numSamples number of envelope values
 | 
			
		||||
        to an AudioBuffer.
 | 
			
		||||
 | 
			
		||||
        @see getNextSample
 | 
			
		||||
    */
 | 
			
		||||
    template<typename FloatType>
 | 
			
		||||
    void applyEnvelopeToBuffer (AudioBuffer<FloatType>& buffer, int startSample, int numSamples)
 | 
			
		||||
    {
 | 
			
		||||
        jassert (startSample + numSamples <= buffer.getNumSamples());
 | 
			
		||||
 | 
			
		||||
        auto numChannels = buffer.getNumChannels();
 | 
			
		||||
 | 
			
		||||
        while (--numSamples >= 0)
 | 
			
		||||
        {
 | 
			
		||||
            auto env = getNextSample();
 | 
			
		||||
 | 
			
		||||
            for (int i = 0; i < numChannels; ++i)
 | 
			
		||||
                buffer.getWritePointer (i)[startSample] *= env;
 | 
			
		||||
 | 
			
		||||
            ++startSample;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    void calculateRates (const Parameters& parameters)
 | 
			
		||||
    {
 | 
			
		||||
        // need to call setSampleRate() first!
 | 
			
		||||
        jassert (sr > 0.0);
 | 
			
		||||
 | 
			
		||||
        attackRate  = (parameters.attack  > 0.0f ? static_cast<float> (1.0f                  / (parameters.attack * sr))  : -1.0f);
 | 
			
		||||
        decayRate   = (parameters.decay   > 0.0f ? static_cast<float> ((1.0f - sustainLevel) / (parameters.decay * sr))   : -1.0f);
 | 
			
		||||
        releaseRate = (parameters.release > 0.0f ? static_cast<float> (sustainLevel          / (parameters.release * sr)) : -1.0f);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void checkCurrentState()
 | 
			
		||||
    {
 | 
			
		||||
        if      (currentState == State::attack  && attackRate <= 0.0f)   currentState = decayRate > 0.0f ? State::decay : State::sustain;
 | 
			
		||||
        else if (currentState == State::decay   && decayRate <= 0.0f)    currentState = State::sustain;
 | 
			
		||||
        else if (currentState == State::release && releaseRate <= 0.0f)  reset();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    enum class State { idle, attack, decay, sustain, release };
 | 
			
		||||
 | 
			
		||||
    State currentState = State::idle;
 | 
			
		||||
    Parameters currentParameters;
 | 
			
		||||
 | 
			
		||||
    double sr = 0.0;
 | 
			
		||||
    float envelopeVal = 0.0f, sustainLevel = 0.0f, attackRate = 0.0f, decayRate = 0.0f, releaseRate = 0.0f;
 | 
			
		||||
    bool resetReleaseRate = false;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
@ -242,6 +242,10 @@ namespace
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        subSamplePos = pos;
 | 
			
		||||
 | 
			
		||||
        if (wrap == 0)
 | 
			
		||||
            return (int) (in - originalIn);
 | 
			
		||||
 | 
			
		||||
        return ((int) (in - originalIn) + wrap) % wrap;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -353,6 +357,10 @@ namespace
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        subSamplePos = pos;
 | 
			
		||||
 | 
			
		||||
        if (wrap == 0)
 | 
			
		||||
            return (int) (in - originalIn);
 | 
			
		||||
 | 
			
		||||
        return ((int) (in - originalIn) + wrap) % wrap;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -49,22 +49,13 @@ public:
 | 
			
		||||
    /** Holds the parameters being used by a Reverb object. */
 | 
			
		||||
    struct Parameters
 | 
			
		||||
    {
 | 
			
		||||
        Parameters() noexcept
 | 
			
		||||
          : roomSize   (0.5f),
 | 
			
		||||
            damping    (0.5f),
 | 
			
		||||
            wetLevel   (0.33f),
 | 
			
		||||
            dryLevel   (0.4f),
 | 
			
		||||
            width      (1.0f),
 | 
			
		||||
            freezeMode (0)
 | 
			
		||||
        {}
 | 
			
		||||
 | 
			
		||||
        float roomSize;     /**< Room size, 0 to 1.0, where 1.0 is big, 0 is small. */
 | 
			
		||||
        float damping;      /**< Damping, 0 to 1.0, where 0 is not damped, 1.0 is fully damped. */
 | 
			
		||||
        float wetLevel;     /**< Wet level, 0 to 1.0 */
 | 
			
		||||
        float dryLevel;     /**< Dry level, 0 to 1.0 */
 | 
			
		||||
        float width;        /**< Reverb width, 0 to 1.0, where 1.0 is very wide. */
 | 
			
		||||
        float freezeMode;   /**< Freeze mode - values < 0.5 are "normal" mode, values > 0.5
 | 
			
		||||
                                 put the reverb into a continuous feedback loop. */
 | 
			
		||||
        float roomSize   = 0.5f;     /**< Room size, 0 to 1.0, where 1.0 is big, 0 is small. */
 | 
			
		||||
        float damping    = 0.5f;     /**< Damping, 0 to 1.0, where 0 is not damped, 1.0 is fully damped. */
 | 
			
		||||
        float wetLevel   = 0.33f;    /**< Wet level, 0 to 1.0 */
 | 
			
		||||
        float dryLevel   = 0.4f;     /**< Dry level, 0 to 1.0 */
 | 
			
		||||
        float width      = 1.0f;     /**< Reverb width, 0 to 1.0, where 1.0 is very wide. */
 | 
			
		||||
        float freezeMode = 0.0f;     /**< Freeze mode - values < 0.5 are "normal" mode, values > 0.5
 | 
			
		||||
                                          put the reverb into a continuous feedback loop. */
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
@ -81,9 +72,9 @@ public:
 | 
			
		||||
        const float dryScaleFactor = 2.0f;
 | 
			
		||||
 | 
			
		||||
        const float wet = newParams.wetLevel * wetScaleFactor;
 | 
			
		||||
        dryGain.setValue (newParams.dryLevel * dryScaleFactor);
 | 
			
		||||
        wetGain1.setValue (0.5f * wet * (1.0f + newParams.width));
 | 
			
		||||
        wetGain2.setValue (0.5f * wet * (1.0f - newParams.width));
 | 
			
		||||
        dryGain.setTargetValue (newParams.dryLevel * dryScaleFactor);
 | 
			
		||||
        wetGain1.setTargetValue (0.5f * wet * (1.0f + newParams.width));
 | 
			
		||||
        wetGain2.setTargetValue (0.5f * wet * (1.0f - newParams.width));
 | 
			
		||||
 | 
			
		||||
        gain = isFrozen (newParams.freezeMode) ? 0.0f : 0.015f;
 | 
			
		||||
        parameters = newParams;
 | 
			
		||||
@ -216,15 +207,15 @@ private:
 | 
			
		||||
 | 
			
		||||
    void setDamping (const float dampingToUse, const float roomSizeToUse) noexcept
 | 
			
		||||
    {
 | 
			
		||||
        damping.setValue (dampingToUse);
 | 
			
		||||
        feedback.setValue (roomSizeToUse);
 | 
			
		||||
        damping.setTargetValue (dampingToUse);
 | 
			
		||||
        feedback.setTargetValue (roomSizeToUse);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    class CombFilter
 | 
			
		||||
    {
 | 
			
		||||
    public:
 | 
			
		||||
        CombFilter() noexcept   : bufferSize (0), bufferIndex (0), last (0)  {}
 | 
			
		||||
        CombFilter() noexcept {}
 | 
			
		||||
 | 
			
		||||
        void setSize (const int size)
 | 
			
		||||
        {
 | 
			
		||||
@ -259,8 +250,8 @@ private:
 | 
			
		||||
 | 
			
		||||
    private:
 | 
			
		||||
        HeapBlock<float> buffer;
 | 
			
		||||
        int bufferSize, bufferIndex;
 | 
			
		||||
        float last;
 | 
			
		||||
        int bufferSize = 0, bufferIndex = 0;
 | 
			
		||||
        float last = 0.0f;
 | 
			
		||||
 | 
			
		||||
        JUCE_DECLARE_NON_COPYABLE (CombFilter)
 | 
			
		||||
    };
 | 
			
		||||
@ -269,7 +260,7 @@ private:
 | 
			
		||||
    class AllPassFilter
 | 
			
		||||
    {
 | 
			
		||||
    public:
 | 
			
		||||
        AllPassFilter() noexcept  : bufferSize (0), bufferIndex (0) {}
 | 
			
		||||
        AllPassFilter() noexcept {}
 | 
			
		||||
 | 
			
		||||
        void setSize (const int size)
 | 
			
		||||
        {
 | 
			
		||||
@ -300,7 +291,7 @@ private:
 | 
			
		||||
 | 
			
		||||
    private:
 | 
			
		||||
        HeapBlock<float> buffer;
 | 
			
		||||
        int bufferSize, bufferIndex;
 | 
			
		||||
        int bufferSize = 0, bufferIndex = 0;
 | 
			
		||||
 | 
			
		||||
        JUCE_DECLARE_NON_COPYABLE (AllPassFilter)
 | 
			
		||||
    };
 | 
			
		||||
@ -314,7 +305,7 @@ private:
 | 
			
		||||
    CombFilter comb [numChannels][numCombs];
 | 
			
		||||
    AllPassFilter allPass [numChannels][numAllPasses];
 | 
			
		||||
 | 
			
		||||
    LinearSmoothedValue<float> damping, feedback, dryGain, wetGain1, wetGain2;
 | 
			
		||||
    SmoothedValue<float> damping, feedback, dryGain, wetGain1, wetGain2;
 | 
			
		||||
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Reverb)
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										92
									
								
								modules/juce_audio_basics/utilities/juce_SmoothedValue.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										92
									
								
								modules/juce_audio_basics/utilities/juce_SmoothedValue.cpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,92 @@
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2018 - ROLI Ltd.
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   The code included in this file is provided under the terms of the ISC license
 | 
			
		||||
   http://www.isc.org/downloads/software-support-policy/isc-license. Permission
 | 
			
		||||
   To use, copy, modify, and/or distribute this software for any purpose with or
 | 
			
		||||
   without fee is hereby granted provided that the above copyright notice and
 | 
			
		||||
   this permission notice appear in all copies.
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
#if JUCE_UNIT_TESTS
 | 
			
		||||
 | 
			
		||||
static CommonSmoothedValueTests <SmoothedValue<float, ValueSmoothingTypes::Linear>> commonLinearSmoothedValueTests;
 | 
			
		||||
static CommonSmoothedValueTests <SmoothedValue<float, ValueSmoothingTypes::Multiplicative>> commonMultiplicativeSmoothedValueTests;
 | 
			
		||||
 | 
			
		||||
class SmoothedValueTests  : public UnitTest
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    SmoothedValueTests()
 | 
			
		||||
        : UnitTest ("SmoothedValueTests", "SmoothedValues")
 | 
			
		||||
    {}
 | 
			
		||||
 | 
			
		||||
    void runTest() override
 | 
			
		||||
    {
 | 
			
		||||
        beginTest ("Linear moving target");
 | 
			
		||||
        {
 | 
			
		||||
            SmoothedValue<float, ValueSmoothingTypes::Linear> sv;
 | 
			
		||||
 | 
			
		||||
            sv.reset (12);
 | 
			
		||||
            float initialValue = 0.0f;
 | 
			
		||||
            sv.setCurrentAndTargetValue (initialValue);
 | 
			
		||||
            sv.setTargetValue (1.0f);
 | 
			
		||||
 | 
			
		||||
            auto delta = sv.getNextValue() - initialValue;
 | 
			
		||||
 | 
			
		||||
            sv.skip (6);
 | 
			
		||||
 | 
			
		||||
            auto newInitialValue = sv.getCurrentValue();
 | 
			
		||||
            sv.setTargetValue (newInitialValue + 2.0f);
 | 
			
		||||
            auto doubleDelta = sv.getNextValue() - newInitialValue;
 | 
			
		||||
 | 
			
		||||
            expectWithinAbsoluteError (doubleDelta, delta * 2.0f, 1.0e-7f);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        beginTest ("Multiplicative curve");
 | 
			
		||||
        {
 | 
			
		||||
            SmoothedValue<double, ValueSmoothingTypes::Multiplicative> sv;
 | 
			
		||||
 | 
			
		||||
            auto numSamples = 12;
 | 
			
		||||
            AudioBuffer<double> values (2, numSamples + 1);
 | 
			
		||||
 | 
			
		||||
            sv.reset (numSamples);
 | 
			
		||||
            sv.setCurrentAndTargetValue (1.0);
 | 
			
		||||
            sv.setTargetValue (2.0f);
 | 
			
		||||
 | 
			
		||||
            values.setSample (0, 0, sv.getCurrentValue());
 | 
			
		||||
 | 
			
		||||
            for (int i = 1; i < values.getNumSamples(); ++i)
 | 
			
		||||
                values.setSample (0, i, sv.getNextValue());
 | 
			
		||||
 | 
			
		||||
            sv.setTargetValue (1.0f);
 | 
			
		||||
            values.setSample (1, values.getNumSamples() - 1, sv.getCurrentValue());
 | 
			
		||||
 | 
			
		||||
            for (int i = values.getNumSamples() - 2; i >= 0 ; --i)
 | 
			
		||||
                values.setSample (1, i, sv.getNextValue());
 | 
			
		||||
 | 
			
		||||
            for (int i = 0; i < values.getNumSamples(); ++i)
 | 
			
		||||
                expectWithinAbsoluteError (values.getSample (0, i), values.getSample (1, i), 1.0e-9);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static SmoothedValueTests smoothedValueTests;
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
							
								
								
									
										622
									
								
								modules/juce_audio_basics/utilities/juce_SmoothedValue.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										622
									
								
								modules/juce_audio_basics/utilities/juce_SmoothedValue.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,622 @@
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2017 - ROLI Ltd.
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   The code included in this file is provided under the terms of the ISC license
 | 
			
		||||
   http://www.isc.org/downloads/software-support-policy/isc-license. Permission
 | 
			
		||||
   To use, copy, modify, and/or distribute this software for any purpose with or
 | 
			
		||||
   without fee is hereby granted provided that the above copyright notice and
 | 
			
		||||
   this permission notice appear in all copies.
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
/**
 | 
			
		||||
    A base class for the smoothed value classes.
 | 
			
		||||
 | 
			
		||||
    This class is used to provide common functionality to the SmoothedValue and
 | 
			
		||||
    dsp::LogRampedValue classes.
 | 
			
		||||
 | 
			
		||||
    @tags{Audio}
 | 
			
		||||
*/
 | 
			
		||||
template <typename SmoothedValueType>
 | 
			
		||||
class SmoothedValueBase
 | 
			
		||||
{
 | 
			
		||||
private:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    template <typename T> struct FloatTypeHelper;
 | 
			
		||||
 | 
			
		||||
    template <template <typename> class SmoothedValueClass, typename FloatType>
 | 
			
		||||
    struct FloatTypeHelper <SmoothedValueClass <FloatType>>
 | 
			
		||||
    {
 | 
			
		||||
        using Type = FloatType;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    template <template <typename, typename> class SmoothedValueClass, typename FloatType, typename SmoothingType>
 | 
			
		||||
    struct FloatTypeHelper <SmoothedValueClass <FloatType, SmoothingType>>
 | 
			
		||||
    {
 | 
			
		||||
        using Type = FloatType;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
    using FloatType = typename FloatTypeHelper<SmoothedValueType>::Type;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Constructor. */
 | 
			
		||||
    SmoothedValueBase() = default;
 | 
			
		||||
 | 
			
		||||
    virtual ~SmoothedValueBase() {}
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Returns true if the current value is currently being interpolated. */
 | 
			
		||||
    bool isSmoothing() const noexcept                    { return countdown > 0; }
 | 
			
		||||
 | 
			
		||||
    /** Returns the current value of the ramp. */
 | 
			
		||||
    FloatType getCurrentValue() const noexcept           { return currentValue; }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Returns the target value towards which the smoothed value is currently moving. */
 | 
			
		||||
    FloatType getTargetValue() const noexcept            { return target; }
 | 
			
		||||
 | 
			
		||||
    /** Sets the current value and the target value.
 | 
			
		||||
        @param newValue    the new value to take
 | 
			
		||||
    */
 | 
			
		||||
    void setCurrentAndTargetValue (FloatType newValue)
 | 
			
		||||
    {
 | 
			
		||||
        target = currentValue = newValue;
 | 
			
		||||
        countdown = 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Applies a smoothed gain to a stream of samples
 | 
			
		||||
        S[i] *= gain
 | 
			
		||||
        @param samples Pointer to a raw array of samples
 | 
			
		||||
        @param numSamples Length of array of samples
 | 
			
		||||
    */
 | 
			
		||||
    void applyGain (FloatType* samples, int numSamples) noexcept
 | 
			
		||||
    {
 | 
			
		||||
        jassert (numSamples >= 0);
 | 
			
		||||
 | 
			
		||||
        if (isSmoothing())
 | 
			
		||||
        {
 | 
			
		||||
            for (int i = 0; i < numSamples; ++i)
 | 
			
		||||
                samples[i] *= getNextSmoothedValue();
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            FloatVectorOperations::multiply (samples, target, numSamples);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Computes output as a smoothed gain applied to a stream of samples.
 | 
			
		||||
        Sout[i] = Sin[i] * gain
 | 
			
		||||
        @param samplesOut A pointer to a raw array of output samples
 | 
			
		||||
        @param samplesIn  A pointer to a raw array of input samples
 | 
			
		||||
        @param numSamples The length of the array of samples
 | 
			
		||||
    */
 | 
			
		||||
    void applyGain (FloatType* samplesOut, const FloatType* samplesIn, int numSamples) noexcept
 | 
			
		||||
    {
 | 
			
		||||
        jassert (numSamples >= 0);
 | 
			
		||||
 | 
			
		||||
        if (isSmoothing())
 | 
			
		||||
        {
 | 
			
		||||
            for (int i = 0; i < numSamples; ++i)
 | 
			
		||||
                samplesOut[i] = samplesIn[i] * getNextSmoothedValue();
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            FloatVectorOperations::multiply (samplesOut, samplesIn, target, numSamples);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Applies a smoothed gain to a buffer */
 | 
			
		||||
    void applyGain (AudioBuffer<FloatType>& buffer, int numSamples) noexcept
 | 
			
		||||
    {
 | 
			
		||||
        jassert (numSamples >= 0);
 | 
			
		||||
 | 
			
		||||
        if (isSmoothing())
 | 
			
		||||
        {
 | 
			
		||||
            if (buffer.getNumChannels() == 1)
 | 
			
		||||
            {
 | 
			
		||||
                auto* samples = buffer.getWritePointer (0);
 | 
			
		||||
 | 
			
		||||
                for (int i = 0; i < numSamples; ++i)
 | 
			
		||||
                    samples[i] *= getNextSmoothedValue();
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                for (auto i = 0; i < numSamples; ++i)
 | 
			
		||||
                {
 | 
			
		||||
                    auto gain = getNextSmoothedValue();
 | 
			
		||||
 | 
			
		||||
                    for (int channel = 0; channel < buffer.getNumChannels(); channel++)
 | 
			
		||||
                        buffer.setSample (channel, i, buffer.getSample (channel, i) * gain);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            buffer.applyGain (0, numSamples, target);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    FloatType getNextSmoothedValue() noexcept
 | 
			
		||||
    {
 | 
			
		||||
        return static_cast <SmoothedValueType*> (this)->getNextValue();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
protected:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    FloatType currentValue = 0;
 | 
			
		||||
    FloatType target = currentValue;
 | 
			
		||||
    int countdown = 0;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
/**
 | 
			
		||||
    A namespace containing a set of types used for specifying the smoothing
 | 
			
		||||
    behaviour of the SmoothedValue class.
 | 
			
		||||
 | 
			
		||||
    For example:
 | 
			
		||||
    @code
 | 
			
		||||
    SmoothedValue<float, ValueSmoothingTypes::Multiplicative> frequency (1.0f);
 | 
			
		||||
    @endcode
 | 
			
		||||
*/
 | 
			
		||||
namespace ValueSmoothingTypes
 | 
			
		||||
{
 | 
			
		||||
    /** Used to indicate a linear smoothing between values. */
 | 
			
		||||
    struct Linear {};
 | 
			
		||||
 | 
			
		||||
    /** Used to indicate a smoothing between multiplicative values. */
 | 
			
		||||
    struct Multiplicative {};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
/**
 | 
			
		||||
    A utility class for values that need smoothing to avoid audio glitches.
 | 
			
		||||
 | 
			
		||||
    A ValueSmoothingTypes::Linear template parameter selects linear smoothing,
 | 
			
		||||
    which increments the SmoothedValue linearly towards its target value.
 | 
			
		||||
 | 
			
		||||
    @code
 | 
			
		||||
    SmoothedValue<float, ValueSmoothingTypes::Linear> yourSmoothedValue;
 | 
			
		||||
    @endcode
 | 
			
		||||
 | 
			
		||||
    A ValueSmoothingTypes::Multiplicative template parameter selects
 | 
			
		||||
    multiplicative smoothing increments towards the target value.
 | 
			
		||||
 | 
			
		||||
    @code
 | 
			
		||||
    SmoothedValue<float, ValueSmoothingTypes::Multiplicative> yourSmoothedValue;
 | 
			
		||||
    @endcode
 | 
			
		||||
 | 
			
		||||
    Multiplicative smoothing is useful when you are dealing with
 | 
			
		||||
    exponential/logarithmic values like volume in dB or frequency in Hz. For
 | 
			
		||||
    example a 12 step ramp from 440.0 Hz (A4) to 880.0 Hz (A5) will increase the
 | 
			
		||||
    frequency with an equal temperament tuning across the octave. A 10 step
 | 
			
		||||
    smoothing from 1.0 (0 dB) to 3.16228 (10 dB) will increase the value in
 | 
			
		||||
    increments of 1 dB.
 | 
			
		||||
 | 
			
		||||
    Note that when you are using multiplicative smoothing you cannot ever reach a
 | 
			
		||||
    target value of zero!
 | 
			
		||||
 | 
			
		||||
    @tags{Audio}
 | 
			
		||||
*/
 | 
			
		||||
template <typename FloatType, typename SmoothingType = ValueSmoothingTypes::Linear>
 | 
			
		||||
class SmoothedValue   : public SmoothedValueBase <SmoothedValue <FloatType, SmoothingType>>
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Constructor. */
 | 
			
		||||
    SmoothedValue() noexcept
 | 
			
		||||
        : SmoothedValue ((FloatType) (std::is_same<SmoothingType, ValueSmoothingTypes::Linear>::value ? 0 : 1))
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Constructor. */
 | 
			
		||||
    SmoothedValue (FloatType initialValue) noexcept
 | 
			
		||||
    {
 | 
			
		||||
        // Multiplicative smoothed values cannot ever reach 0!
 | 
			
		||||
        jassert (! (std::is_same<SmoothingType, ValueSmoothingTypes::Multiplicative>::value && initialValue == 0));
 | 
			
		||||
 | 
			
		||||
        // Visual Studio can't handle base class initialisation with CRTP
 | 
			
		||||
        this->currentValue = initialValue;
 | 
			
		||||
        this->target = this->currentValue;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Reset to a new sample rate and ramp length.
 | 
			
		||||
        @param sampleRate           The sample rate
 | 
			
		||||
        @param rampLengthInSeconds  The duration of the ramp in seconds
 | 
			
		||||
    */
 | 
			
		||||
    void reset (double sampleRate, double rampLengthInSeconds) noexcept
 | 
			
		||||
    {
 | 
			
		||||
        jassert (sampleRate > 0 && rampLengthInSeconds >= 0);
 | 
			
		||||
        reset ((int) std::floor (rampLengthInSeconds * sampleRate));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Set a new ramp length directly in samples.
 | 
			
		||||
        @param numSteps     The number of samples over which the ramp should be active
 | 
			
		||||
    */
 | 
			
		||||
    void reset (int numSteps) noexcept
 | 
			
		||||
    {
 | 
			
		||||
        stepsToTarget = numSteps;
 | 
			
		||||
        this->setCurrentAndTargetValue (this->target);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Set the next value to ramp towards.
 | 
			
		||||
        @param newValue     The new target value
 | 
			
		||||
    */
 | 
			
		||||
    void setTargetValue (FloatType newValue) noexcept
 | 
			
		||||
    {
 | 
			
		||||
        if (newValue == this->target)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        if (stepsToTarget <= 0)
 | 
			
		||||
        {
 | 
			
		||||
            this->setCurrentAndTargetValue (newValue);
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Multiplicative smoothed values cannot ever reach 0!
 | 
			
		||||
        jassert (! (std::is_same<SmoothingType, ValueSmoothingTypes::Multiplicative>::value && newValue == 0));
 | 
			
		||||
 | 
			
		||||
        this->target = newValue;
 | 
			
		||||
        this->countdown = stepsToTarget;
 | 
			
		||||
 | 
			
		||||
        setStepSize();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Compute the next value.
 | 
			
		||||
        @returns Smoothed value
 | 
			
		||||
    */
 | 
			
		||||
    FloatType getNextValue() noexcept
 | 
			
		||||
    {
 | 
			
		||||
        if (! this->isSmoothing())
 | 
			
		||||
            return this->target;
 | 
			
		||||
 | 
			
		||||
        --(this->countdown);
 | 
			
		||||
 | 
			
		||||
        if (this->isSmoothing())
 | 
			
		||||
            setNextValue();
 | 
			
		||||
        else
 | 
			
		||||
            this->currentValue = this->target;
 | 
			
		||||
 | 
			
		||||
        return this->currentValue;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Skip the next numSamples samples.
 | 
			
		||||
        This is identical to calling getNextValue numSamples times. It returns
 | 
			
		||||
        the new current value.
 | 
			
		||||
        @see getNextValue
 | 
			
		||||
    */
 | 
			
		||||
    FloatType skip (int numSamples) noexcept
 | 
			
		||||
    {
 | 
			
		||||
        if (numSamples >= this->countdown)
 | 
			
		||||
        {
 | 
			
		||||
            this->setCurrentAndTargetValue (this->target);
 | 
			
		||||
            return this->target;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        skipCurrentValue (numSamples);
 | 
			
		||||
 | 
			
		||||
        this->countdown -= numSamples;
 | 
			
		||||
        return this->currentValue;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** THIS FUNCTION IS DEPRECATED.
 | 
			
		||||
 | 
			
		||||
        Use `setTargetValue (float)` and `setCurrentAndTargetValue()` instead:
 | 
			
		||||
 | 
			
		||||
        lsv.setValue (x, false); -> lsv.setTargetValue (x);
 | 
			
		||||
        lsv.setValue (x, true);  -> lsv.setCurrentAndTargetValue (x);
 | 
			
		||||
 | 
			
		||||
        @param newValue     The new target value
 | 
			
		||||
        @param force        If true, the value will be set immediately, bypassing the ramp
 | 
			
		||||
    */
 | 
			
		||||
    JUCE_DEPRECATED_WITH_BODY (void setValue (FloatType newValue, bool force = false) noexcept,
 | 
			
		||||
    {
 | 
			
		||||
        if (force)
 | 
			
		||||
        {
 | 
			
		||||
            this->setCurrentAndTargetValue (newValue);
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        setTargetValue (newValue);
 | 
			
		||||
    })
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    template <typename T>
 | 
			
		||||
    using LinearVoid = typename std::enable_if <std::is_same <T, ValueSmoothingTypes::Linear>::value, void>::type;
 | 
			
		||||
 | 
			
		||||
    template <typename T>
 | 
			
		||||
    using MultiplicativeVoid = typename std::enable_if <std::is_same <T, ValueSmoothingTypes::Multiplicative>::value, void>::type;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    template <typename T = SmoothingType>
 | 
			
		||||
    LinearVoid<T> setStepSize() noexcept
 | 
			
		||||
    {
 | 
			
		||||
        step = (this->target - this->currentValue) / (FloatType) this->countdown;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template <typename T = SmoothingType>
 | 
			
		||||
    MultiplicativeVoid<T> setStepSize()
 | 
			
		||||
    {
 | 
			
		||||
        step = std::exp ((std::log (std::abs (this->target)) - std::log (std::abs (this->currentValue))) / this->countdown);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    template <typename T = SmoothingType>
 | 
			
		||||
    LinearVoid<T> setNextValue() noexcept
 | 
			
		||||
    {
 | 
			
		||||
        this->currentValue += step;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template <typename T = SmoothingType>
 | 
			
		||||
    MultiplicativeVoid<T> setNextValue() noexcept
 | 
			
		||||
    {
 | 
			
		||||
        this->currentValue *= step;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    template <typename T = SmoothingType>
 | 
			
		||||
    LinearVoid<T> skipCurrentValue (int numSamples) noexcept
 | 
			
		||||
    {
 | 
			
		||||
        this->currentValue += step * (FloatType) numSamples;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template <typename T = SmoothingType>
 | 
			
		||||
    MultiplicativeVoid<T> skipCurrentValue (int numSamples)
 | 
			
		||||
    {
 | 
			
		||||
        this->currentValue *= (FloatType) std::pow (step, numSamples);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    FloatType step = FloatType();
 | 
			
		||||
    int stepsToTarget = 0;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <typename FloatType>
 | 
			
		||||
using LinearSmoothedValue = SmoothedValue <FloatType, ValueSmoothingTypes::Linear>;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
//==============================================================================
 | 
			
		||||
#if JUCE_UNIT_TESTS
 | 
			
		||||
 | 
			
		||||
template <class SmoothedValueType>
 | 
			
		||||
class CommonSmoothedValueTests  : public UnitTest
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    CommonSmoothedValueTests()
 | 
			
		||||
        : UnitTest ("CommonSmoothedValueTests", "SmoothedValues")
 | 
			
		||||
    {}
 | 
			
		||||
 | 
			
		||||
    void runTest() override
 | 
			
		||||
    {
 | 
			
		||||
        beginTest ("Initial state");
 | 
			
		||||
        {
 | 
			
		||||
            SmoothedValueType sv;
 | 
			
		||||
 | 
			
		||||
            auto value = sv.getCurrentValue();
 | 
			
		||||
            expectEquals (sv.getTargetValue(), value);
 | 
			
		||||
 | 
			
		||||
            sv.getNextValue();
 | 
			
		||||
            expectEquals (sv.getCurrentValue(), value);
 | 
			
		||||
            expect (! sv.isSmoothing());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        beginTest ("Resetting");
 | 
			
		||||
        {
 | 
			
		||||
            auto initialValue = 15.0f;
 | 
			
		||||
 | 
			
		||||
            SmoothedValueType sv (initialValue);
 | 
			
		||||
            sv.reset (3);
 | 
			
		||||
            expectEquals (sv.getCurrentValue(), initialValue);
 | 
			
		||||
 | 
			
		||||
            auto targetValue = initialValue + 1.0f;
 | 
			
		||||
            sv.setTargetValue (targetValue);
 | 
			
		||||
            expectEquals (sv.getTargetValue(), targetValue);
 | 
			
		||||
            expectEquals (sv.getCurrentValue(), initialValue);
 | 
			
		||||
            expect (sv.isSmoothing());
 | 
			
		||||
 | 
			
		||||
            auto currentValue = sv.getNextValue();
 | 
			
		||||
            expect (currentValue > initialValue);
 | 
			
		||||
            expectEquals (sv.getCurrentValue(), currentValue);
 | 
			
		||||
            expectEquals (sv.getTargetValue(), targetValue);
 | 
			
		||||
            expect (sv.isSmoothing());
 | 
			
		||||
 | 
			
		||||
            sv.reset (5);
 | 
			
		||||
 | 
			
		||||
            expectEquals (sv.getCurrentValue(), targetValue);
 | 
			
		||||
            expectEquals (sv.getTargetValue(),  targetValue);
 | 
			
		||||
            expect (! sv.isSmoothing());
 | 
			
		||||
 | 
			
		||||
            sv.getNextValue();
 | 
			
		||||
            expectEquals (sv.getCurrentValue(), targetValue);
 | 
			
		||||
 | 
			
		||||
            sv.setTargetValue (1.5f);
 | 
			
		||||
            sv.getNextValue();
 | 
			
		||||
 | 
			
		||||
            float newStart = 0.2f;
 | 
			
		||||
            sv.setCurrentAndTargetValue (newStart);
 | 
			
		||||
            expectEquals (sv.getNextValue(), newStart);
 | 
			
		||||
            expectEquals (sv.getTargetValue(), newStart);
 | 
			
		||||
            expectEquals (sv.getCurrentValue(), newStart);
 | 
			
		||||
            expect (! sv.isSmoothing());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        beginTest ("Sample rate");
 | 
			
		||||
        {
 | 
			
		||||
            SmoothedValueType svSamples { 3.0f };
 | 
			
		||||
            auto svTime = svSamples;
 | 
			
		||||
 | 
			
		||||
            auto numSamples = 12;
 | 
			
		||||
 | 
			
		||||
            svSamples.reset (numSamples);
 | 
			
		||||
            svTime.reset (numSamples * 2, 1.0);
 | 
			
		||||
 | 
			
		||||
            for (int i = 0; i < numSamples; ++i)
 | 
			
		||||
            {
 | 
			
		||||
                svTime.skip (1);
 | 
			
		||||
                expectWithinAbsoluteError (svSamples.getNextValue(),
 | 
			
		||||
                                           svTime.getNextValue(),
 | 
			
		||||
                                           1.0e-7f);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        beginTest ("Block processing");
 | 
			
		||||
        {
 | 
			
		||||
            SmoothedValueType sv (1.0f);
 | 
			
		||||
 | 
			
		||||
            sv.reset (12);
 | 
			
		||||
            sv.setTargetValue (2.0f);
 | 
			
		||||
 | 
			
		||||
            const auto numSamples = 15;
 | 
			
		||||
 | 
			
		||||
            AudioBuffer<float> referenceData (1, numSamples);
 | 
			
		||||
 | 
			
		||||
            for (int i = 0; i < numSamples; ++i)
 | 
			
		||||
                referenceData.setSample (0, i, sv.getNextValue());
 | 
			
		||||
 | 
			
		||||
            expect (referenceData.getSample (0, 0) > 0);
 | 
			
		||||
            expect (referenceData.getSample (0, 10) < sv.getTargetValue());
 | 
			
		||||
            expectWithinAbsoluteError (referenceData.getSample (0, 11),
 | 
			
		||||
                                       sv.getTargetValue(),
 | 
			
		||||
                                       1.0e-7f);
 | 
			
		||||
 | 
			
		||||
            auto getUnitData = [] (int numSamplesToGenerate)
 | 
			
		||||
            {
 | 
			
		||||
                AudioBuffer<float> result (1, numSamplesToGenerate);
 | 
			
		||||
 | 
			
		||||
                for (int i = 0; i < numSamplesToGenerate; ++i)
 | 
			
		||||
                    result.setSample (0, i, 1.0f);
 | 
			
		||||
 | 
			
		||||
                return result;
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            auto compareData = [this](const AudioBuffer<float>& test,
 | 
			
		||||
                                      const AudioBuffer<float>& reference)
 | 
			
		||||
            {
 | 
			
		||||
                for (int i = 0; i < test.getNumSamples(); ++i)
 | 
			
		||||
                    expectWithinAbsoluteError (test.getSample (0, i),
 | 
			
		||||
                                               reference.getSample (0, i),
 | 
			
		||||
                                               1.0e-7f);
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            auto testData = getUnitData (numSamples);
 | 
			
		||||
            sv.setCurrentAndTargetValue (1.0f);
 | 
			
		||||
            sv.setTargetValue (2.0f);
 | 
			
		||||
            sv.applyGain (testData.getWritePointer (0), numSamples);
 | 
			
		||||
            compareData (testData, referenceData);
 | 
			
		||||
 | 
			
		||||
            testData = getUnitData (numSamples);
 | 
			
		||||
            AudioBuffer<float> destData (1, numSamples);
 | 
			
		||||
            sv.setCurrentAndTargetValue (1.0f);
 | 
			
		||||
            sv.setTargetValue (2.0f);
 | 
			
		||||
            sv.applyGain (destData.getWritePointer (0),
 | 
			
		||||
                           testData.getReadPointer (0),
 | 
			
		||||
                           numSamples);
 | 
			
		||||
            compareData (destData, referenceData);
 | 
			
		||||
            compareData (testData, getUnitData (numSamples));
 | 
			
		||||
 | 
			
		||||
            testData = getUnitData (numSamples);
 | 
			
		||||
            sv.setCurrentAndTargetValue (1.0f);
 | 
			
		||||
            sv.setTargetValue (2.0f);
 | 
			
		||||
            sv.applyGain (testData, numSamples);
 | 
			
		||||
            compareData (testData, referenceData);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        beginTest ("Skip");
 | 
			
		||||
        {
 | 
			
		||||
            SmoothedValueType sv;
 | 
			
		||||
 | 
			
		||||
            sv.reset (12);
 | 
			
		||||
            sv.setCurrentAndTargetValue (1.0f);
 | 
			
		||||
            sv.setTargetValue (2.0f);
 | 
			
		||||
 | 
			
		||||
            Array<float> reference;
 | 
			
		||||
 | 
			
		||||
            for (int i = 0; i < 15; ++i)
 | 
			
		||||
                reference.add (sv.getNextValue());
 | 
			
		||||
 | 
			
		||||
            sv.setCurrentAndTargetValue (1.0f);
 | 
			
		||||
            sv.setTargetValue (2.0f);
 | 
			
		||||
 | 
			
		||||
            expectWithinAbsoluteError (sv.skip (1), reference[0], 1.0e-6f);
 | 
			
		||||
            expectWithinAbsoluteError (sv.skip (1), reference[1], 1.0e-6f);
 | 
			
		||||
            expectWithinAbsoluteError (sv.skip (2), reference[3], 1.0e-6f);
 | 
			
		||||
            sv.skip (3);
 | 
			
		||||
            expectWithinAbsoluteError (sv.getCurrentValue(), reference[6], 1.0e-6f);
 | 
			
		||||
            expectEquals (sv.skip (300), sv.getTargetValue());
 | 
			
		||||
            expectEquals (sv.getCurrentValue(), sv.getTargetValue());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        beginTest ("Negative");
 | 
			
		||||
        {
 | 
			
		||||
            SmoothedValueType sv;
 | 
			
		||||
 | 
			
		||||
            auto numValues = 12;
 | 
			
		||||
            sv.reset (numValues);
 | 
			
		||||
 | 
			
		||||
            std::vector<std::pair<float, float>> ranges = { { -1.0f, -2.0f },
 | 
			
		||||
                                                            { -100.0f, -3.0f } };
 | 
			
		||||
 | 
			
		||||
            for (auto range : ranges)
 | 
			
		||||
            {
 | 
			
		||||
                auto start = range.first, end = range.second;
 | 
			
		||||
 | 
			
		||||
                sv.setCurrentAndTargetValue (start);
 | 
			
		||||
                sv.setTargetValue (end);
 | 
			
		||||
 | 
			
		||||
                auto val = sv.skip (numValues / 2);
 | 
			
		||||
 | 
			
		||||
                if (end > start)
 | 
			
		||||
                    expect (val > start && val < end);
 | 
			
		||||
                else
 | 
			
		||||
                    expect (val < start && val > end);
 | 
			
		||||
 | 
			
		||||
                auto nextVal = sv.getNextValue();
 | 
			
		||||
                expect (end > start ? (nextVal > val) : (nextVal < val));
 | 
			
		||||
 | 
			
		||||
                auto endVal = sv.skip (500);
 | 
			
		||||
                expectEquals (endVal, end);
 | 
			
		||||
                expectEquals (sv.getNextValue(), end);
 | 
			
		||||
                expectEquals (sv.getCurrentValue(), end);
 | 
			
		||||
 | 
			
		||||
                sv.setCurrentAndTargetValue (start);
 | 
			
		||||
                sv.setTargetValue (end);
 | 
			
		||||
 | 
			
		||||
                SmoothedValueType positiveSv { -start };
 | 
			
		||||
                positiveSv.reset (numValues);
 | 
			
		||||
                positiveSv.setTargetValue (-end);
 | 
			
		||||
 | 
			
		||||
                for (int i = 0; i < numValues + 2; ++i)
 | 
			
		||||
                    expectEquals (sv.getNextValue(), -positiveSv.getNextValue());
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
		Reference in New Issue
	
	Block a user