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:
Alex Birch
2019-06-22 20:41:38 +01:00
parent d22c2cd4fa
commit 9ee566b251
1140 changed files with 67534 additions and 105952 deletions

View File

@ -39,10 +39,10 @@ class JUCE_API AudioPlayHead
{
protected:
//==============================================================================
AudioPlayHead() {}
AudioPlayHead() = default;
public:
virtual ~AudioPlayHead() {}
virtual ~AudioPlayHead() = default;
//==============================================================================
/** Frame rate types. */

View File

@ -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;
}

View File

@ -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". */

View File

@ -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");

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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)
{

View File

@ -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

View File

@ -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

View File

@ -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"

View File

@ -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"

View File

@ -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)
{

View File

@ -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;

View File

@ -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)
};

View File

@ -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.

View File

@ -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;

View File

@ -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,

View File

@ -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)

View File

@ -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.

View File

@ -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); }

View File

@ -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))
{

View File

@ -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

View File

@ -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() };

View File

@ -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());

View File

@ -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)
};

View File

@ -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();

View File

@ -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)
};

View File

@ -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

View File

@ -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.

View File

@ -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. */

View File

@ -56,7 +56,7 @@ public:
bool deleteSourceWhenDeleted);
/** Destructor. */
~ChannelRemappingAudioSource();
~ChannelRemappingAudioSource() override;
//==============================================================================
/** Specifies a number of channels that this audio source must produce from its

View File

@ -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. */

View File

@ -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

View File

@ -41,7 +41,7 @@ public:
MixerAudioSource();
/** Destructor. */
~MixerAudioSource();
~MixerAudioSource() override;
//==============================================================================
/** Adds an input source to the mixer.

View File

@ -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.

View File

@ -47,7 +47,7 @@ public:
int numChannels = 2);
/** Destructor. */
~ResamplingAudioSource();
~ResamplingAudioSource() override;
/** Changes the resampling ratio.

View File

@ -44,7 +44,7 @@ public:
bool deleteInputWhenDeleted);
/** Destructor. */
~ReverbAudioSource();
~ReverbAudioSource() override;
//==============================================================================
/** Returns the parameters from the reverb. */

View File

@ -38,7 +38,7 @@ public:
ToneGeneratorAudioSource();
/** Destructor. */
~ToneGeneratorAudioSource();
~ToneGeneratorAudioSource() override;
//==============================================================================
/** Sets the signal's amplitude. */

View File

@ -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))

View File

@ -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; }

View 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

View File

@ -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;
}

View File

@ -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)
};

View 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

View 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