- Library code update
- project update (added Eigen) git-svn-id: http://moon:8086/svn/software/trunk/projects/mpsk_rx_gui@94 b431acfa-c32f-4a4a-93f1-934dc6c82436
This commit is contained in:
@@ -35,11 +35,13 @@
|
||||
using namespace juce;
|
||||
#endif
|
||||
|
||||
#if ! JUCE_DONT_DECLARE_PROJECTINFO
|
||||
namespace ProjectInfo
|
||||
{
|
||||
const char* const projectName = "M-QAM Transceiver";
|
||||
const char* const versionString = "1.0.0";
|
||||
const int versionNumber = 0x10000;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // __APPHEADERFILE_GMZMR9__
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
void AudioDataConverters::convertFloatToInt16LE (const float* source, void* dest, int numSamples, const int destBytesPerSample)
|
||||
{
|
||||
const double maxVal = (double) 0x7fff;
|
||||
char* intData = static_cast <char*> (dest);
|
||||
char* intData = static_cast<char*> (dest);
|
||||
|
||||
if (dest != (void*) source || destBytesPerSample <= 4)
|
||||
{
|
||||
@@ -50,7 +50,7 @@ void AudioDataConverters::convertFloatToInt16LE (const float* source, void* dest
|
||||
void AudioDataConverters::convertFloatToInt16BE (const float* source, void* dest, int numSamples, const int destBytesPerSample)
|
||||
{
|
||||
const double maxVal = (double) 0x7fff;
|
||||
char* intData = static_cast <char*> (dest);
|
||||
char* intData = static_cast<char*> (dest);
|
||||
|
||||
if (dest != (void*) source || destBytesPerSample <= 4)
|
||||
{
|
||||
@@ -75,7 +75,7 @@ void AudioDataConverters::convertFloatToInt16BE (const float* source, void* dest
|
||||
void AudioDataConverters::convertFloatToInt24LE (const float* source, void* dest, int numSamples, const int destBytesPerSample)
|
||||
{
|
||||
const double maxVal = (double) 0x7fffff;
|
||||
char* intData = static_cast <char*> (dest);
|
||||
char* intData = static_cast<char*> (dest);
|
||||
|
||||
if (dest != (void*) source || destBytesPerSample <= 4)
|
||||
{
|
||||
@@ -100,7 +100,7 @@ void AudioDataConverters::convertFloatToInt24LE (const float* source, void* dest
|
||||
void AudioDataConverters::convertFloatToInt24BE (const float* source, void* dest, int numSamples, const int destBytesPerSample)
|
||||
{
|
||||
const double maxVal = (double) 0x7fffff;
|
||||
char* intData = static_cast <char*> (dest);
|
||||
char* intData = static_cast<char*> (dest);
|
||||
|
||||
if (dest != (void*) source || destBytesPerSample <= 4)
|
||||
{
|
||||
@@ -125,7 +125,7 @@ void AudioDataConverters::convertFloatToInt24BE (const float* source, void* dest
|
||||
void AudioDataConverters::convertFloatToInt32LE (const float* source, void* dest, int numSamples, const int destBytesPerSample)
|
||||
{
|
||||
const double maxVal = (double) 0x7fffffff;
|
||||
char* intData = static_cast <char*> (dest);
|
||||
char* intData = static_cast<char*> (dest);
|
||||
|
||||
if (dest != (void*) source || destBytesPerSample <= 4)
|
||||
{
|
||||
@@ -150,7 +150,7 @@ void AudioDataConverters::convertFloatToInt32LE (const float* source, void* dest
|
||||
void AudioDataConverters::convertFloatToInt32BE (const float* source, void* dest, int numSamples, const int destBytesPerSample)
|
||||
{
|
||||
const double maxVal = (double) 0x7fffffff;
|
||||
char* intData = static_cast <char*> (dest);
|
||||
char* intData = static_cast<char*> (dest);
|
||||
|
||||
if (dest != (void*) source || destBytesPerSample <= 4)
|
||||
{
|
||||
@@ -176,7 +176,7 @@ void AudioDataConverters::convertFloatToFloat32LE (const float* source, void* de
|
||||
{
|
||||
jassert (dest != (void*) source || destBytesPerSample <= 4); // This op can't be performed on in-place data!
|
||||
|
||||
char* d = static_cast <char*> (dest);
|
||||
char* d = static_cast<char*> (dest);
|
||||
|
||||
for (int i = 0; i < numSamples; ++i)
|
||||
{
|
||||
@@ -194,7 +194,7 @@ void AudioDataConverters::convertFloatToFloat32BE (const float* source, void* de
|
||||
{
|
||||
jassert (dest != (void*) source || destBytesPerSample <= 4); // This op can't be performed on in-place data!
|
||||
|
||||
char* d = static_cast <char*> (dest);
|
||||
char* d = static_cast<char*> (dest);
|
||||
|
||||
for (int i = 0; i < numSamples; ++i)
|
||||
{
|
||||
@@ -212,7 +212,7 @@ void AudioDataConverters::convertFloatToFloat32BE (const float* source, void* de
|
||||
void AudioDataConverters::convertInt16LEToFloat (const void* const source, float* const dest, int numSamples, const int srcBytesPerSample)
|
||||
{
|
||||
const float scale = 1.0f / 0x7fff;
|
||||
const char* intData = static_cast <const char*> (source);
|
||||
const char* intData = static_cast<const char*> (source);
|
||||
|
||||
if (source != (void*) dest || srcBytesPerSample >= 4)
|
||||
{
|
||||
@@ -237,7 +237,7 @@ void AudioDataConverters::convertInt16LEToFloat (const void* const source, float
|
||||
void AudioDataConverters::convertInt16BEToFloat (const void* const source, float* const dest, int numSamples, const int srcBytesPerSample)
|
||||
{
|
||||
const float scale = 1.0f / 0x7fff;
|
||||
const char* intData = static_cast <const char*> (source);
|
||||
const char* intData = static_cast<const char*> (source);
|
||||
|
||||
if (source != (void*) dest || srcBytesPerSample >= 4)
|
||||
{
|
||||
@@ -262,7 +262,7 @@ void AudioDataConverters::convertInt16BEToFloat (const void* const source, float
|
||||
void AudioDataConverters::convertInt24LEToFloat (const void* const source, float* const dest, int numSamples, const int srcBytesPerSample)
|
||||
{
|
||||
const float scale = 1.0f / 0x7fffff;
|
||||
const char* intData = static_cast <const char*> (source);
|
||||
const char* intData = static_cast<const char*> (source);
|
||||
|
||||
if (source != (void*) dest || srcBytesPerSample >= 4)
|
||||
{
|
||||
@@ -287,7 +287,7 @@ void AudioDataConverters::convertInt24LEToFloat (const void* const source, float
|
||||
void AudioDataConverters::convertInt24BEToFloat (const void* const source, float* const dest, int numSamples, const int srcBytesPerSample)
|
||||
{
|
||||
const float scale = 1.0f / 0x7fffff;
|
||||
const char* intData = static_cast <const char*> (source);
|
||||
const char* intData = static_cast<const char*> (source);
|
||||
|
||||
if (source != (void*) dest || srcBytesPerSample >= 4)
|
||||
{
|
||||
@@ -312,7 +312,7 @@ void AudioDataConverters::convertInt24BEToFloat (const void* const source, float
|
||||
void AudioDataConverters::convertInt32LEToFloat (const void* const source, float* const dest, int numSamples, const int srcBytesPerSample)
|
||||
{
|
||||
const float scale = 1.0f / 0x7fffffff;
|
||||
const char* intData = static_cast <const char*> (source);
|
||||
const char* intData = static_cast<const char*> (source);
|
||||
|
||||
if (source != (void*) dest || srcBytesPerSample >= 4)
|
||||
{
|
||||
@@ -337,7 +337,7 @@ void AudioDataConverters::convertInt32LEToFloat (const void* const source, float
|
||||
void AudioDataConverters::convertInt32BEToFloat (const void* const source, float* const dest, int numSamples, const int srcBytesPerSample)
|
||||
{
|
||||
const float scale = 1.0f / 0x7fffffff;
|
||||
const char* intData = static_cast <const char*> (source);
|
||||
const char* intData = static_cast<const char*> (source);
|
||||
|
||||
if (source != (void*) dest || srcBytesPerSample >= 4)
|
||||
{
|
||||
@@ -361,7 +361,7 @@ void AudioDataConverters::convertInt32BEToFloat (const void* const source, float
|
||||
|
||||
void AudioDataConverters::convertFloat32LEToFloat (const void* const source, float* const dest, int numSamples, const int srcBytesPerSample)
|
||||
{
|
||||
const char* s = static_cast <const char*> (source);
|
||||
const char* s = static_cast<const char*> (source);
|
||||
|
||||
for (int i = 0; i < numSamples; ++i)
|
||||
{
|
||||
@@ -378,7 +378,7 @@ void AudioDataConverters::convertFloat32LEToFloat (const void* const source, flo
|
||||
|
||||
void AudioDataConverters::convertFloat32BEToFloat (const void* const source, float* const dest, int numSamples, const int srcBytesPerSample)
|
||||
{
|
||||
const char* s = static_cast <const char*> (source);
|
||||
const char* s = static_cast<const char*> (source);
|
||||
|
||||
for (int i = 0; i < numSamples; ++i)
|
||||
{
|
||||
|
||||
@@ -91,7 +91,7 @@ AudioSampleBuffer::AudioSampleBuffer (float* const* dataToReferTo,
|
||||
allocatedBytes (0)
|
||||
{
|
||||
jassert (dataToReferTo != nullptr);
|
||||
jassert (numChans >= 0);
|
||||
jassert (numChans >= 0 && numSamples >= 0);
|
||||
allocateChannels (dataToReferTo, 0);
|
||||
}
|
||||
|
||||
@@ -105,7 +105,7 @@ AudioSampleBuffer::AudioSampleBuffer (float* const* dataToReferTo,
|
||||
isClear (false)
|
||||
{
|
||||
jassert (dataToReferTo != nullptr);
|
||||
jassert (numChans >= 0);
|
||||
jassert (numChans >= 0 && startSample >= 0 && numSamples >= 0);
|
||||
allocateChannels (dataToReferTo, startSample);
|
||||
}
|
||||
|
||||
@@ -114,7 +114,7 @@ void AudioSampleBuffer::setDataToReferTo (float** dataToReferTo,
|
||||
const int newNumSamples) noexcept
|
||||
{
|
||||
jassert (dataToReferTo != nullptr);
|
||||
jassert (newNumChannels >= 0);
|
||||
jassert (newNumChannels >= 0 && newNumSamples >= 0);
|
||||
|
||||
allocatedBytes = 0;
|
||||
allocatedData.free();
|
||||
@@ -128,6 +128,8 @@ void AudioSampleBuffer::setDataToReferTo (float** dataToReferTo,
|
||||
|
||||
void AudioSampleBuffer::allocateChannels (float* const* const dataToReferTo, int offset)
|
||||
{
|
||||
jassert (offset >= 0);
|
||||
|
||||
// (try to avoid doing a malloc here, as that'll blow up things like Pro-Tools)
|
||||
if (numChannels < (int) numElementsInArray (preallocatedChannelSpace))
|
||||
{
|
||||
@@ -163,6 +165,8 @@ AudioSampleBuffer& AudioSampleBuffer::operator= (const AudioSampleBuffer& other)
|
||||
}
|
||||
else
|
||||
{
|
||||
isClear = false;
|
||||
|
||||
for (int i = 0; i < numChannels; ++i)
|
||||
FloatVectorOperations::copy (channels[i], other.channels[i], size);
|
||||
}
|
||||
|
||||
@@ -24,8 +24,9 @@
|
||||
|
||||
namespace FloatVectorHelpers
|
||||
{
|
||||
#define JUCE_INCREMENT_SRC_DEST dest += (16 / sizeof (*dest)); src += (16 / sizeof (*dest));
|
||||
#define JUCE_INCREMENT_DEST dest += (16 / sizeof (*dest));
|
||||
#define JUCE_INCREMENT_SRC_DEST dest += (16 / sizeof (*dest)); src += (16 / sizeof (*dest));
|
||||
#define JUCE_INCREMENT_SRC1_SRC2_DEST dest += (16 / sizeof (*dest)); src1 += (16 / sizeof (*dest)); src2 += (16 / sizeof (*dest));
|
||||
#define JUCE_INCREMENT_DEST dest += (16 / sizeof (*dest));
|
||||
|
||||
#if JUCE_USE_SSE_INTRINSICS
|
||||
static bool sse2Present = false;
|
||||
@@ -122,6 +123,17 @@ namespace FloatVectorHelpers
|
||||
} \
|
||||
JUCE_FINISH_VEC_OP (normalOp)
|
||||
|
||||
#define JUCE_PERFORM_VEC_OP_SRC1_SRC2_DEST(normalOp, vecOp, locals, increment, setupOp) \
|
||||
JUCE_BEGIN_VEC_OP \
|
||||
setupOp \
|
||||
{ \
|
||||
Mode::ParallelType (&loadSrc1) (const Mode::Type* v) = FloatVectorHelpers::isAligned (src1) ? Mode::loadA : Mode::loadU; \
|
||||
Mode::ParallelType (&loadSrc2) (const Mode::Type* v) = FloatVectorHelpers::isAligned (src2) ? Mode::loadA : Mode::loadU; \
|
||||
void (&storeDst) (Mode::Type* dest, Mode::ParallelType a) = FloatVectorHelpers::isAligned (dest) ? Mode::storeA : Mode::storeU; \
|
||||
JUCE_VEC_LOOP_TWO_SOURCES (vecOp, loadSrc1, loadSrc2, storeDst, locals, increment); \
|
||||
} \
|
||||
JUCE_FINISH_VEC_OP (normalOp)
|
||||
|
||||
//==============================================================================
|
||||
#elif JUCE_USE_ARM_NEON
|
||||
|
||||
@@ -193,6 +205,12 @@ namespace FloatVectorHelpers
|
||||
JUCE_VEC_LOOP (vecOp, Mode::loadU, Mode::loadU, Mode::storeU, locals, increment) \
|
||||
JUCE_FINISH_VEC_OP (normalOp)
|
||||
|
||||
#define JUCE_PERFORM_VEC_OP_SRC1_SRC2_DEST(normalOp, vecOp, locals, increment, setupOp) \
|
||||
JUCE_BEGIN_VEC_OP \
|
||||
setupOp \
|
||||
JUCE_VEC_LOOP_TWO_SOURCES (vecOp, Mode::loadU, Mode::loadU, Mode::storeU, locals, increment) \
|
||||
JUCE_FINISH_VEC_OP (normalOp)
|
||||
|
||||
//==============================================================================
|
||||
#else
|
||||
#define JUCE_PERFORM_VEC_OP_DEST(normalOp, vecOp, locals, setupOp) \
|
||||
@@ -201,6 +219,8 @@ namespace FloatVectorHelpers
|
||||
#define JUCE_PERFORM_VEC_OP_SRC_DEST(normalOp, vecOp, locals, increment, setupOp) \
|
||||
for (int i = 0; i < num; ++i) normalOp;
|
||||
|
||||
#define JUCE_PERFORM_VEC_OP_SRC1_SRC2_DEST(normalOp, vecOp, locals, increment, setupOp) \
|
||||
for (int i = 0; i < num; ++i) normalOp;
|
||||
#endif
|
||||
|
||||
//==============================================================================
|
||||
@@ -212,10 +232,19 @@ namespace FloatVectorHelpers
|
||||
increment; \
|
||||
}
|
||||
|
||||
#define JUCE_VEC_LOOP_TWO_SOURCES(vecOp, src1Load, src2Load, dstStore, locals, increment) \
|
||||
for (int i = 0; i < numLongOps; ++i) \
|
||||
{ \
|
||||
locals (src1Load, src2Load); \
|
||||
dstStore (dest, vecOp); \
|
||||
increment; \
|
||||
}
|
||||
|
||||
#define JUCE_LOAD_NONE(srcLoad, dstLoad)
|
||||
#define JUCE_LOAD_DEST(srcLoad, dstLoad) const Mode::ParallelType d = dstLoad (dest);
|
||||
#define JUCE_LOAD_SRC(srcLoad, dstLoad) const Mode::ParallelType s = srcLoad (src);
|
||||
#define JUCE_LOAD_SRC_DEST(srcLoad, dstLoad) const Mode::ParallelType d = dstLoad (dest), s = srcLoad (src);
|
||||
#define JUCE_LOAD_DEST(srcLoad, dstLoad) const Mode::ParallelType d = dstLoad (dest);
|
||||
#define JUCE_LOAD_SRC(srcLoad, dstLoad) const Mode::ParallelType s = srcLoad (src);
|
||||
#define JUCE_LOAD_SRC1_SRC2(src1Load, src2Load) const Mode::ParallelType s1 = src1Load (src1), s2 = src2Load (src2);
|
||||
#define JUCE_LOAD_SRC_DEST(srcLoad, dstLoad) const Mode::ParallelType d = dstLoad (dest), s = srcLoad (src);
|
||||
|
||||
#if JUCE_USE_SSE_INTRINSICS || JUCE_USE_ARM_NEON
|
||||
template<int typeSize> struct ModeType { typedef BasicOps32 Mode; };
|
||||
@@ -229,7 +258,7 @@ namespace FloatVectorHelpers
|
||||
|
||||
static Type findMinOrMax (const Type* src, int num, const bool isMinimum) noexcept
|
||||
{
|
||||
const int numLongOps = num / Mode::numParallel;
|
||||
int numLongOps = num / Mode::numParallel;
|
||||
|
||||
#if JUCE_USE_SSE_INTRINSICS
|
||||
if (numLongOps > 1 && isSSE2Available())
|
||||
@@ -246,7 +275,7 @@ namespace FloatVectorHelpers
|
||||
|
||||
if (isMinimum)
|
||||
{
|
||||
for (int i = 1; i < numLongOps; ++i)
|
||||
while (--numLongOps > 0)
|
||||
{
|
||||
src += Mode::numParallel;
|
||||
val = Mode::min (val, Mode::loadA (src));
|
||||
@@ -254,7 +283,7 @@ namespace FloatVectorHelpers
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 1; i < numLongOps; ++i)
|
||||
while (--numLongOps > 0)
|
||||
{
|
||||
src += Mode::numParallel;
|
||||
val = Mode::max (val, Mode::loadA (src));
|
||||
@@ -268,7 +297,7 @@ namespace FloatVectorHelpers
|
||||
|
||||
if (isMinimum)
|
||||
{
|
||||
for (int i = 1; i < numLongOps; ++i)
|
||||
while (--numLongOps > 0)
|
||||
{
|
||||
src += Mode::numParallel;
|
||||
val = Mode::min (val, Mode::loadU (src));
|
||||
@@ -276,7 +305,7 @@ namespace FloatVectorHelpers
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 1; i < numLongOps; ++i)
|
||||
while (--numLongOps > 0)
|
||||
{
|
||||
src += Mode::numParallel;
|
||||
val = Mode::max (val, Mode::loadU (src));
|
||||
@@ -288,6 +317,7 @@ namespace FloatVectorHelpers
|
||||
: Mode::max (val);
|
||||
|
||||
num &= (Mode::numParallel - 1);
|
||||
src += Mode::numParallel;
|
||||
|
||||
for (int i = 0; i < num; ++i)
|
||||
result = isMinimum ? jmin (result, src[i])
|
||||
@@ -302,7 +332,7 @@ namespace FloatVectorHelpers
|
||||
|
||||
static Range<Type> findMinAndMax (const Type* src, int num) noexcept
|
||||
{
|
||||
const int numLongOps = num / Mode::numParallel;
|
||||
int numLongOps = num / Mode::numParallel;
|
||||
|
||||
#if JUCE_USE_SSE_INTRINSICS
|
||||
if (numLongOps > 1 && isSSE2Available())
|
||||
@@ -318,7 +348,7 @@ namespace FloatVectorHelpers
|
||||
mn = Mode::loadA (src);
|
||||
mx = mn;
|
||||
|
||||
for (int i = 1; i < numLongOps; ++i)
|
||||
while (--numLongOps > 0)
|
||||
{
|
||||
src += Mode::numParallel;
|
||||
const ParallelType v = Mode::loadA (src);
|
||||
@@ -332,7 +362,7 @@ namespace FloatVectorHelpers
|
||||
mn = Mode::loadU (src);
|
||||
mx = mn;
|
||||
|
||||
for (int i = 1; i < numLongOps; ++i)
|
||||
while (--numLongOps > 0)
|
||||
{
|
||||
src += Mode::numParallel;
|
||||
const ParallelType v = Mode::loadU (src);
|
||||
@@ -344,7 +374,9 @@ namespace FloatVectorHelpers
|
||||
Range<Type> result (Mode::min (mn),
|
||||
Mode::max (mx));
|
||||
|
||||
num &= 3;
|
||||
num &= (Mode::numParallel - 1);
|
||||
src += Mode::numParallel;
|
||||
|
||||
for (int i = 0; i < num; ++i)
|
||||
result = result.getUnionWith (src[i]);
|
||||
|
||||
@@ -409,7 +441,7 @@ void JUCE_CALLTYPE FloatVectorOperations::copy (double* dest, const double* src,
|
||||
void JUCE_CALLTYPE FloatVectorOperations::copyWithMultiply (float* dest, const float* src, float multiplier, int num) noexcept
|
||||
{
|
||||
#if JUCE_USE_VDSP_FRAMEWORK
|
||||
vDSP_vsmul (src, 1, &multiplier, dest, 1, num);
|
||||
vDSP_vsmul (src, 1, &multiplier, dest, 1, (vDSP_Length) num);
|
||||
#else
|
||||
JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] = src[i] * multiplier, Mode::mul (mult, s),
|
||||
JUCE_LOAD_SRC, JUCE_INCREMENT_SRC_DEST,
|
||||
@@ -420,7 +452,7 @@ void JUCE_CALLTYPE FloatVectorOperations::copyWithMultiply (float* dest, const f
|
||||
void JUCE_CALLTYPE FloatVectorOperations::copyWithMultiply (double* dest, const double* src, double multiplier, int num) noexcept
|
||||
{
|
||||
#if JUCE_USE_VDSP_FRAMEWORK
|
||||
vDSP_vsmulD (src, 1, &multiplier, dest, 1, num);
|
||||
vDSP_vsmulD (src, 1, &multiplier, dest, 1, (vDSP_Length) num);
|
||||
#else
|
||||
JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] = src[i] * multiplier, Mode::mul (mult, s),
|
||||
JUCE_LOAD_SRC, JUCE_INCREMENT_SRC_DEST,
|
||||
@@ -440,10 +472,32 @@ void JUCE_CALLTYPE FloatVectorOperations::add (double* dest, double amount, int
|
||||
const Mode::ParallelType amountToAdd = Mode::load1 (amount);)
|
||||
}
|
||||
|
||||
void JUCE_CALLTYPE FloatVectorOperations::add (float* dest, float* src, float amount, int num) noexcept
|
||||
{
|
||||
#if JUCE_USE_VDSP_FRAMEWORK
|
||||
vDSP_vsadd (src, 1, &amount, dest, 1, (vDSP_Length) num);
|
||||
#else
|
||||
JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] = src[i] + amount, Mode::add (am, s),
|
||||
JUCE_LOAD_SRC, JUCE_INCREMENT_SRC_DEST,
|
||||
const Mode::ParallelType am = Mode::load1 (amount);)
|
||||
#endif
|
||||
}
|
||||
|
||||
void JUCE_CALLTYPE FloatVectorOperations::add (double* dest, double* src, double amount, int num) noexcept
|
||||
{
|
||||
#if JUCE_USE_VDSP_FRAMEWORK
|
||||
vDSP_vsaddD (src, 1, &amount, dest, 1, (vDSP_Length) num);
|
||||
#else
|
||||
JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] = src[i] + amount, Mode::add (am, s),
|
||||
JUCE_LOAD_SRC, JUCE_INCREMENT_SRC_DEST,
|
||||
const Mode::ParallelType am = Mode::load1 (amount);)
|
||||
#endif
|
||||
}
|
||||
|
||||
void JUCE_CALLTYPE FloatVectorOperations::add (float* dest, const float* src, int num) noexcept
|
||||
{
|
||||
#if JUCE_USE_VDSP_FRAMEWORK
|
||||
vDSP_vadd (src, 1, dest, 1, dest, 1, num);
|
||||
vDSP_vadd (src, 1, dest, 1, dest, 1, (vDSP_Length) num);
|
||||
#else
|
||||
JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] += src[i], Mode::add (d, s), JUCE_LOAD_SRC_DEST, JUCE_INCREMENT_SRC_DEST, )
|
||||
#endif
|
||||
@@ -452,16 +506,34 @@ void JUCE_CALLTYPE FloatVectorOperations::add (float* dest, const float* src, in
|
||||
void JUCE_CALLTYPE FloatVectorOperations::add (double* dest, const double* src, int num) noexcept
|
||||
{
|
||||
#if JUCE_USE_VDSP_FRAMEWORK
|
||||
vDSP_vaddD (src, 1, dest, 1, dest, 1, num);
|
||||
vDSP_vaddD (src, 1, dest, 1, dest, 1, (vDSP_Length) num);
|
||||
#else
|
||||
JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] += src[i], Mode::add (d, s), JUCE_LOAD_SRC_DEST, JUCE_INCREMENT_SRC_DEST, )
|
||||
#endif
|
||||
}
|
||||
|
||||
void JUCE_CALLTYPE FloatVectorOperations::add (float* dest, const float* src1, const float* src2, int num) noexcept
|
||||
{
|
||||
#if JUCE_USE_VDSP_FRAMEWORK
|
||||
vDSP_vadd (src1, 1, src2, 1, dest, 1, (vDSP_Length) num);
|
||||
#else
|
||||
JUCE_PERFORM_VEC_OP_SRC1_SRC2_DEST (dest[i] = src1[i] + src2[i], Mode::add (s1, s2), JUCE_LOAD_SRC1_SRC2, JUCE_INCREMENT_SRC1_SRC2_DEST, )
|
||||
#endif
|
||||
}
|
||||
|
||||
void JUCE_CALLTYPE FloatVectorOperations::add (double* dest, const double* src1, const double* src2, int num) noexcept
|
||||
{
|
||||
#if JUCE_USE_VDSP_FRAMEWORK
|
||||
vDSP_vaddD (src1, 1, src2, 1, dest, 1, (vDSP_Length) num);
|
||||
#else
|
||||
JUCE_PERFORM_VEC_OP_SRC1_SRC2_DEST (dest[i] = src1[i] + src2[i], Mode::add (s1, s2), JUCE_LOAD_SRC1_SRC2, JUCE_INCREMENT_SRC1_SRC2_DEST, )
|
||||
#endif
|
||||
}
|
||||
|
||||
void JUCE_CALLTYPE FloatVectorOperations::subtract (float* dest, const float* src, int num) noexcept
|
||||
{
|
||||
#if JUCE_USE_VDSP_FRAMEWORK
|
||||
vDSP_vsub (src, 1, dest, 1, dest, 1, num);
|
||||
vDSP_vsub (src, 1, dest, 1, dest, 1, (vDSP_Length) num);
|
||||
#else
|
||||
JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] -= src[i], Mode::sub (d, s), JUCE_LOAD_SRC_DEST, JUCE_INCREMENT_SRC_DEST, )
|
||||
#endif
|
||||
@@ -470,12 +542,30 @@ void JUCE_CALLTYPE FloatVectorOperations::subtract (float* dest, const float* sr
|
||||
void JUCE_CALLTYPE FloatVectorOperations::subtract (double* dest, const double* src, int num) noexcept
|
||||
{
|
||||
#if JUCE_USE_VDSP_FRAMEWORK
|
||||
vDSP_vsubD (src, 1, dest, 1, dest, 1, num);
|
||||
vDSP_vsubD (src, 1, dest, 1, dest, 1, (vDSP_Length) num);
|
||||
#else
|
||||
JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] -= src[i], Mode::sub (d, s), JUCE_LOAD_SRC_DEST, JUCE_INCREMENT_SRC_DEST, )
|
||||
#endif
|
||||
}
|
||||
|
||||
void JUCE_CALLTYPE FloatVectorOperations::subtract (float* dest, const float* src1, const float* src2, int num) noexcept
|
||||
{
|
||||
#if JUCE_USE_VDSP_FRAMEWORK
|
||||
vDSP_vsub (src2, 1, src1, 1, dest, 1, (vDSP_Length) num);
|
||||
#else
|
||||
JUCE_PERFORM_VEC_OP_SRC1_SRC2_DEST (dest[i] = src1[i] - src2[i], Mode::sub (s1, s2), JUCE_LOAD_SRC1_SRC2, JUCE_INCREMENT_SRC1_SRC2_DEST, )
|
||||
#endif
|
||||
}
|
||||
|
||||
void JUCE_CALLTYPE FloatVectorOperations::subtract (double* dest, const double* src1, const double* src2, int num) noexcept
|
||||
{
|
||||
#if JUCE_USE_VDSP_FRAMEWORK
|
||||
vDSP_vsubD (src2, 1, src1, 1, dest, 1, (vDSP_Length) num);
|
||||
#else
|
||||
JUCE_PERFORM_VEC_OP_SRC1_SRC2_DEST (dest[i] = src1[i] - src2[i], Mode::sub (s1, s2), JUCE_LOAD_SRC1_SRC2, JUCE_INCREMENT_SRC1_SRC2_DEST, )
|
||||
#endif
|
||||
}
|
||||
|
||||
void JUCE_CALLTYPE FloatVectorOperations::addWithMultiply (float* dest, const float* src, float multiplier, int num) noexcept
|
||||
{
|
||||
JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] += src[i] * multiplier, Mode::add (d, Mode::mul (mult, s)),
|
||||
@@ -493,7 +583,7 @@ void JUCE_CALLTYPE FloatVectorOperations::addWithMultiply (double* dest, const d
|
||||
void JUCE_CALLTYPE FloatVectorOperations::multiply (float* dest, const float* src, int num) noexcept
|
||||
{
|
||||
#if JUCE_USE_VDSP_FRAMEWORK
|
||||
vDSP_vmul (src, 1, dest, 1, dest, 1, num);
|
||||
vDSP_vmul (src, 1, dest, 1, dest, 1, (vDSP_Length) num);
|
||||
#else
|
||||
JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] *= src[i], Mode::mul (d, s), JUCE_LOAD_SRC_DEST, JUCE_INCREMENT_SRC_DEST, )
|
||||
#endif
|
||||
@@ -502,16 +592,34 @@ void JUCE_CALLTYPE FloatVectorOperations::multiply (float* dest, const float* sr
|
||||
void JUCE_CALLTYPE FloatVectorOperations::multiply (double* dest, const double* src, int num) noexcept
|
||||
{
|
||||
#if JUCE_USE_VDSP_FRAMEWORK
|
||||
vDSP_vmulD (src, 1, dest, 1, dest, 1, num);
|
||||
vDSP_vmulD (src, 1, dest, 1, dest, 1, (vDSP_Length) num);
|
||||
#else
|
||||
JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] *= src[i], Mode::mul (d, s), JUCE_LOAD_SRC_DEST, JUCE_INCREMENT_SRC_DEST, )
|
||||
#endif
|
||||
}
|
||||
|
||||
void JUCE_CALLTYPE FloatVectorOperations::multiply (float* dest, const float* src1, const float* src2, int num) noexcept
|
||||
{
|
||||
#if JUCE_USE_VDSP_FRAMEWORK
|
||||
vDSP_vmul (src1, 1, src2, 1, dest, 1, (vDSP_Length) num);
|
||||
#else
|
||||
JUCE_PERFORM_VEC_OP_SRC1_SRC2_DEST (dest[i] = src1[i] * src2[i], Mode::mul (s1, s2), JUCE_LOAD_SRC1_SRC2, JUCE_INCREMENT_SRC1_SRC2_DEST, )
|
||||
#endif
|
||||
}
|
||||
|
||||
void JUCE_CALLTYPE FloatVectorOperations::multiply (double* dest, const double* src1, const double* src2, int num) noexcept
|
||||
{
|
||||
#if JUCE_USE_VDSP_FRAMEWORK
|
||||
vDSP_vmulD (src1, 1, src2, 1, dest, 1, (vDSP_Length) num);
|
||||
#else
|
||||
JUCE_PERFORM_VEC_OP_SRC1_SRC2_DEST (dest[i] = src1[i] * src2[i], Mode::mul (s1, s2), JUCE_LOAD_SRC1_SRC2, JUCE_INCREMENT_SRC1_SRC2_DEST, )
|
||||
#endif
|
||||
}
|
||||
|
||||
void JUCE_CALLTYPE FloatVectorOperations::multiply (float* dest, float multiplier, int num) noexcept
|
||||
{
|
||||
#if JUCE_USE_VDSP_FRAMEWORK
|
||||
vDSP_vsmul (dest, 1, &multiplier, dest, 1, num);
|
||||
vDSP_vsmul (dest, 1, &multiplier, dest, 1, (vDSP_Length) num);
|
||||
#else
|
||||
JUCE_PERFORM_VEC_OP_DEST (dest[i] *= multiplier, Mode::mul (d, mult), JUCE_LOAD_DEST,
|
||||
const Mode::ParallelType mult = Mode::load1 (multiplier);)
|
||||
@@ -521,13 +629,27 @@ void JUCE_CALLTYPE FloatVectorOperations::multiply (float* dest, float multiplie
|
||||
void JUCE_CALLTYPE FloatVectorOperations::multiply (double* dest, double multiplier, int num) noexcept
|
||||
{
|
||||
#if JUCE_USE_VDSP_FRAMEWORK
|
||||
vDSP_vsmulD (dest, 1, &multiplier, dest, 1, num);
|
||||
vDSP_vsmulD (dest, 1, &multiplier, dest, 1, (vDSP_Length) num);
|
||||
#else
|
||||
JUCE_PERFORM_VEC_OP_DEST (dest[i] *= multiplier, Mode::mul (d, mult), JUCE_LOAD_DEST,
|
||||
const Mode::ParallelType mult = Mode::load1 (multiplier);)
|
||||
#endif
|
||||
}
|
||||
|
||||
void JUCE_CALLTYPE FloatVectorOperations::multiply (float* dest, const float* src, float multiplier, int num) noexcept
|
||||
{
|
||||
JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] = src[i] * multiplier, Mode::mul (mult, s),
|
||||
JUCE_LOAD_SRC, JUCE_INCREMENT_SRC_DEST,
|
||||
const Mode::ParallelType mult = Mode::load1 (multiplier);)
|
||||
}
|
||||
|
||||
void JUCE_CALLTYPE FloatVectorOperations::multiply (double* dest, const double* src, double multiplier, int num) noexcept
|
||||
{
|
||||
JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] = src[i] * multiplier, Mode::mul (mult, s),
|
||||
JUCE_LOAD_SRC, JUCE_INCREMENT_SRC_DEST,
|
||||
const Mode::ParallelType mult = Mode::load1 (multiplier);)
|
||||
}
|
||||
|
||||
void FloatVectorOperations::negate (float* dest, const float* src, int num) noexcept
|
||||
{
|
||||
#if JUCE_USE_VDSP_FRAMEWORK
|
||||
@@ -640,8 +762,8 @@ public:
|
||||
const int range = random.nextBool() ? 500 : 10;
|
||||
const int num = random.nextInt (range) + 1;
|
||||
|
||||
HeapBlock<ValueType> buffer1 (num + 16), buffer2 (num + 16);
|
||||
HeapBlock<int> buffer3 (num + 16);
|
||||
HeapBlock<ValueType> buffer1 ((size_t) num + 16), buffer2 ((size_t) num + 16);
|
||||
HeapBlock<int> buffer3 ((size_t) num + 16);
|
||||
|
||||
#if JUCE_ARM
|
||||
ValueType* const data1 = buffer1;
|
||||
|
||||
@@ -65,18 +65,36 @@ public:
|
||||
/** Adds a fixed value to the destination values. */
|
||||
static void JUCE_CALLTYPE add (double* dest, double amountToAdd, int numValues) noexcept;
|
||||
|
||||
/** Adds a fixed value to each source value and stores it in the destination array. */
|
||||
static void JUCE_CALLTYPE add (float* dest, float* src, float amount, int numValues) noexcept;
|
||||
|
||||
/** Adds a fixed value to each source value and stores it in the destination array. */
|
||||
static void JUCE_CALLTYPE add (double* dest, double* src, double amount, int numValues) noexcept;
|
||||
|
||||
/** Adds the source values to the destination values. */
|
||||
static void JUCE_CALLTYPE add (float* dest, const float* src, int numValues) noexcept;
|
||||
|
||||
/** Adds the source values to the destination values. */
|
||||
static void JUCE_CALLTYPE add (double* dest, const double* src, int numValues) noexcept;
|
||||
|
||||
/** Adds each source1 value to the corresponding source2 value and stores the result in the destination array. */
|
||||
static void JUCE_CALLTYPE add (float* dest, const float* src1, const float* src2, int num) noexcept;
|
||||
|
||||
/** Adds each source1 value to the corresponding source2 value and stores the result in the destination array. */
|
||||
static void JUCE_CALLTYPE add (double* dest, const double* src1, const double* src2, int num) noexcept;
|
||||
|
||||
/** Subtracts the source values from the destination values. */
|
||||
static void JUCE_CALLTYPE subtract (float* dest, const float* src, int numValues) noexcept;
|
||||
|
||||
/** Subtracts the source values from the destination values. */
|
||||
static void JUCE_CALLTYPE subtract (double* dest, const double* src, int numValues) noexcept;
|
||||
|
||||
/** Subtracts each source2 value from the corresponding source1 value and stores the result in the destination array. */
|
||||
static void JUCE_CALLTYPE subtract (float* dest, const float* src1, const float* src2, int num) noexcept;
|
||||
|
||||
/** Subtracts each source2 value from the corresponding source1 value and stores the result in the destination array. */
|
||||
static void JUCE_CALLTYPE subtract (double* dest, const double* src1, const double* src2, int num) noexcept;
|
||||
|
||||
/** Multiplies each source value by the given multiplier, then adds it to the destination value. */
|
||||
static void JUCE_CALLTYPE addWithMultiply (float* dest, const float* src, float multiplier, int numValues) noexcept;
|
||||
|
||||
@@ -89,12 +107,24 @@ public:
|
||||
/** Multiplies the destination values by the source values. */
|
||||
static void JUCE_CALLTYPE multiply (double* dest, const double* src, int numValues) noexcept;
|
||||
|
||||
/** Multiplies each source1 value by the correspinding source2 value, then stores it in the destination array. */
|
||||
static void JUCE_CALLTYPE multiply (float* dest, const float* src1, const float* src2, int numValues) noexcept;
|
||||
|
||||
/** Multiplies each source1 value by the correspinding source2 value, then stores it in the destination array. */
|
||||
static void JUCE_CALLTYPE multiply (double* dest, const double* src1, const double* src2, int numValues) noexcept;
|
||||
|
||||
/** Multiplies each of the destination values by a fixed multiplier. */
|
||||
static void JUCE_CALLTYPE multiply (float* dest, float multiplier, int numValues) noexcept;
|
||||
|
||||
/** Multiplies each of the destination values by a fixed multiplier. */
|
||||
static void JUCE_CALLTYPE multiply (double* dest, double multiplier, int numValues) noexcept;
|
||||
|
||||
/** Multiplies each of the source values by a fixed multiplier and stores the result in the destination array. */
|
||||
static void JUCE_CALLTYPE multiply (float* dest, const float* src, float multiplier, int num) noexcept;
|
||||
|
||||
/** Multiplies each of the source values by a fixed multiplier and stores the result in the destination array. */
|
||||
static void JUCE_CALLTYPE multiply (double* dest, const double* src, double multiplier, int num) noexcept;
|
||||
|
||||
/** Copies a source vector to a destination, negating each value. */
|
||||
static void JUCE_CALLTYPE negate (float* dest, const float* src, int numValues) noexcept;
|
||||
|
||||
|
||||
@@ -181,7 +181,7 @@ public:
|
||||
for (int j = 0; j < numAllPasses; ++j) // run the allpass filters in series
|
||||
output = allPass[0][j].process (output);
|
||||
|
||||
samples[i] = output * wet1 + input * dry;
|
||||
samples[i] = output * wet1 + samples[i] * dry;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -57,7 +57,9 @@
|
||||
#endif
|
||||
|
||||
#if (JUCE_MAC || JUCE_IOS) && JUCE_USE_VDSP_FRAMEWORK
|
||||
#define Point CarbonDummyPointName // (workaround to avoid definition of "Point" by old Carbon headers)
|
||||
#include <Accelerate/Accelerate.h>
|
||||
#undef Point
|
||||
#else
|
||||
#undef JUCE_USE_VDSP_FRAMEWORK
|
||||
#endif
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"id": "juce_audio_basics",
|
||||
"name": "JUCE audio and midi data classes",
|
||||
"version": "3.0.5",
|
||||
"version": "3.0.8",
|
||||
"description": "Classes for audio buffer manipulation, midi message handling, synthesis, etc",
|
||||
"website": "http://www.juce.com/juce",
|
||||
"license": "GPL/Commercial",
|
||||
|
||||
@@ -210,7 +210,7 @@ bool MidiBuffer::Iterator::getNextEvent (const uint8* &midiData, int& numBytes,
|
||||
const int itemSize = MidiBufferHelpers::getEventDataSize (data);
|
||||
numBytes = itemSize;
|
||||
midiData = data + sizeof (int32) + sizeof (uint16);
|
||||
data += sizeof (int32) + sizeof (uint16) + itemSize;
|
||||
data += sizeof (int32) + sizeof (uint16) + (size_t) itemSize;
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -223,7 +223,7 @@ bool MidiBuffer::Iterator::getNextEvent (MidiMessage& result, int& samplePositio
|
||||
samplePosition = MidiBufferHelpers::getEventTime (data);
|
||||
const int itemSize = MidiBufferHelpers::getEventDataSize (data);
|
||||
result = MidiMessage (data + sizeof (int32) + sizeof (uint16), itemSize, samplePosition);
|
||||
data += sizeof (int32) + sizeof (uint16) + itemSize;
|
||||
data += sizeof (int32) + sizeof (uint16) + (size_t) itemSize;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -186,9 +186,10 @@ public:
|
||||
|
||||
/** Retrieves a copy of the next event from the buffer.
|
||||
|
||||
@param result on return, this will be the message (the MidiMessage's timestamp
|
||||
is not set)
|
||||
@param samplePosition on return, this will be the position of the event
|
||||
@param result on return, this will be the message. The MidiMessage's timestamp
|
||||
is set to the same value as samplePosition.
|
||||
@param samplePosition on return, this will be the position of the event, as a
|
||||
sample index in the buffer
|
||||
@returns true if an event was found, or false if the iterator has reached
|
||||
the end of the buffer
|
||||
*/
|
||||
@@ -203,7 +204,8 @@ public:
|
||||
temporarily until the MidiBuffer is altered.
|
||||
@param numBytesOfMidiData on return, this is the number of bytes of data used by the
|
||||
midi message
|
||||
@param samplePosition on return, this will be the position of the event
|
||||
@param samplePosition on return, this will be the position of the event, as a
|
||||
sample index in the buffer
|
||||
@returns true if an event was found, or false if the iterator has reached
|
||||
the end of the buffer
|
||||
*/
|
||||
|
||||
@@ -129,7 +129,7 @@ MidiMessage::MidiMessage (const MidiMessage& other)
|
||||
{
|
||||
if (other.allocatedData != nullptr)
|
||||
{
|
||||
allocatedData.malloc (size);
|
||||
allocatedData.malloc ((size_t) size);
|
||||
memcpy (allocatedData, other.allocatedData, (size_t) size);
|
||||
}
|
||||
else
|
||||
@@ -143,7 +143,7 @@ MidiMessage::MidiMessage (const MidiMessage& other, const double newTimeStamp)
|
||||
{
|
||||
if (other.allocatedData != nullptr)
|
||||
{
|
||||
allocatedData.malloc (size);
|
||||
allocatedData.malloc ((size_t) size);
|
||||
memcpy (allocatedData, other.allocatedData, (size_t) size);
|
||||
}
|
||||
else
|
||||
@@ -255,7 +255,7 @@ MidiMessage& MidiMessage::operator= (const MidiMessage& other)
|
||||
|
||||
if (other.allocatedData != nullptr)
|
||||
{
|
||||
allocatedData.malloc (size);
|
||||
allocatedData.malloc ((size_t) size);
|
||||
memcpy (allocatedData, other.allocatedData, (size_t) size);
|
||||
}
|
||||
else
|
||||
@@ -297,7 +297,7 @@ uint8* MidiMessage::allocateSpace (int bytes)
|
||||
{
|
||||
if (bytes > 4)
|
||||
{
|
||||
allocatedData.malloc (bytes);
|
||||
allocatedData.malloc ((size_t) bytes);
|
||||
return allocatedData;
|
||||
}
|
||||
|
||||
@@ -661,7 +661,7 @@ String MidiMessage::getTextFromTextMetaEvent() const
|
||||
|
||||
MidiMessage MidiMessage::textMetaEvent (int type, StringRef text)
|
||||
{
|
||||
jassert (type > 0 && type < 16)
|
||||
jassert (type > 0 && type < 16);
|
||||
|
||||
MidiMessage result;
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@ MidiMessageSequence::MidiMessageSequence()
|
||||
MidiMessageSequence::MidiMessageSequence (const MidiMessageSequence& other)
|
||||
{
|
||||
list.addCopiesOf (other.list);
|
||||
updateMatchedPairs();
|
||||
}
|
||||
|
||||
MidiMessageSequence& MidiMessageSequence::operator= (const MidiMessageSequence& other)
|
||||
@@ -52,17 +53,17 @@ void MidiMessageSequence::clear()
|
||||
list.clear();
|
||||
}
|
||||
|
||||
int MidiMessageSequence::getNumEvents() const
|
||||
int MidiMessageSequence::getNumEvents() const noexcept
|
||||
{
|
||||
return list.size();
|
||||
}
|
||||
|
||||
MidiMessageSequence::MidiEventHolder* MidiMessageSequence::getEventPointer (const int index) const
|
||||
MidiMessageSequence::MidiEventHolder* MidiMessageSequence::getEventPointer (const int index) const noexcept
|
||||
{
|
||||
return list [index];
|
||||
}
|
||||
|
||||
double MidiMessageSequence::getTimeOfMatchingKeyUp (const int index) const
|
||||
double MidiMessageSequence::getTimeOfMatchingKeyUp (const int index) const noexcept
|
||||
{
|
||||
if (const MidiEventHolder* const meh = list [index])
|
||||
if (meh->noteOffObject != nullptr)
|
||||
@@ -71,7 +72,7 @@ double MidiMessageSequence::getTimeOfMatchingKeyUp (const int index) const
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
int MidiMessageSequence::getIndexOfMatchingKeyUp (const int index) const
|
||||
int MidiMessageSequence::getIndexOfMatchingKeyUp (const int index) const noexcept
|
||||
{
|
||||
if (const MidiEventHolder* const meh = list [index])
|
||||
return list.indexOf (meh->noteOffObject);
|
||||
@@ -79,12 +80,12 @@ int MidiMessageSequence::getIndexOfMatchingKeyUp (const int index) const
|
||||
return -1;
|
||||
}
|
||||
|
||||
int MidiMessageSequence::getIndexOf (MidiEventHolder* const event) const
|
||||
int MidiMessageSequence::getIndexOf (MidiEventHolder* const event) const noexcept
|
||||
{
|
||||
return list.indexOf (event);
|
||||
}
|
||||
|
||||
int MidiMessageSequence::getNextIndexAtTime (const double timeStamp) const
|
||||
int MidiMessageSequence::getNextIndexAtTime (const double timeStamp) const noexcept
|
||||
{
|
||||
const int numEvents = list.size();
|
||||
|
||||
@@ -97,17 +98,17 @@ int MidiMessageSequence::getNextIndexAtTime (const double timeStamp) const
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
double MidiMessageSequence::getStartTime() const
|
||||
double MidiMessageSequence::getStartTime() const noexcept
|
||||
{
|
||||
return getEventTime (0);
|
||||
}
|
||||
|
||||
double MidiMessageSequence::getEndTime() const
|
||||
double MidiMessageSequence::getEndTime() const noexcept
|
||||
{
|
||||
return getEventTime (list.size() - 1);
|
||||
}
|
||||
|
||||
double MidiMessageSequence::getEventTime (const int index) const
|
||||
double MidiMessageSequence::getEventTime (const int index) const noexcept
|
||||
{
|
||||
if (const MidiEventHolder* const meh = list [index])
|
||||
return meh->message.getTimeStamp();
|
||||
@@ -181,13 +182,13 @@ void MidiMessageSequence::addSequence (const MidiMessageSequence& other,
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void MidiMessageSequence::sort()
|
||||
void MidiMessageSequence::sort() noexcept
|
||||
{
|
||||
MidiMessageSequenceSorter sorter;
|
||||
list.sort (sorter, true);
|
||||
}
|
||||
|
||||
void MidiMessageSequence::updateMatchedPairs()
|
||||
void MidiMessageSequence::updateMatchedPairs() noexcept
|
||||
{
|
||||
for (int i = 0; i < list.size(); ++i)
|
||||
{
|
||||
@@ -226,7 +227,7 @@ void MidiMessageSequence::updateMatchedPairs()
|
||||
}
|
||||
}
|
||||
|
||||
void MidiMessageSequence::addTimeToMessages (const double delta)
|
||||
void MidiMessageSequence::addTimeToMessages (const double delta) noexcept
|
||||
{
|
||||
for (int i = list.size(); --i >= 0;)
|
||||
{
|
||||
|
||||
@@ -91,47 +91,47 @@ public:
|
||||
void clear();
|
||||
|
||||
/** Returns the number of events in the sequence. */
|
||||
int getNumEvents() const;
|
||||
int getNumEvents() const noexcept;
|
||||
|
||||
/** Returns a pointer to one of the events. */
|
||||
MidiEventHolder* getEventPointer (int index) const;
|
||||
MidiEventHolder* getEventPointer (int index) const noexcept;
|
||||
|
||||
/** Returns the time of the note-up that matches the note-on at this index.
|
||||
If the event at this index isn't a note-on, it'll just return 0.
|
||||
@see MidiMessageSequence::MidiEventHolder::noteOffObject
|
||||
*/
|
||||
double getTimeOfMatchingKeyUp (int index) const;
|
||||
double getTimeOfMatchingKeyUp (int index) const noexcept;
|
||||
|
||||
/** Returns the index of the note-up that matches the note-on at this index.
|
||||
If the event at this index isn't a note-on, it'll just return -1.
|
||||
@see MidiMessageSequence::MidiEventHolder::noteOffObject
|
||||
*/
|
||||
int getIndexOfMatchingKeyUp (int index) const;
|
||||
int getIndexOfMatchingKeyUp (int index) const noexcept;
|
||||
|
||||
/** Returns the index of an event. */
|
||||
int getIndexOf (MidiEventHolder* event) const;
|
||||
int getIndexOf (MidiEventHolder* event) const noexcept;
|
||||
|
||||
/** Returns the index of the first event on or after the given timestamp.
|
||||
If the time is beyond the end of the sequence, this will return the
|
||||
number of events.
|
||||
*/
|
||||
int getNextIndexAtTime (double timeStamp) const;
|
||||
int getNextIndexAtTime (double timeStamp) const noexcept;
|
||||
|
||||
//==============================================================================
|
||||
/** Returns the timestamp of the first event in the sequence.
|
||||
@see getEndTime
|
||||
*/
|
||||
double getStartTime() const;
|
||||
double getStartTime() const noexcept;
|
||||
|
||||
/** Returns the timestamp of the last event in the sequence.
|
||||
@see getStartTime
|
||||
*/
|
||||
double getEndTime() const;
|
||||
double getEndTime() const noexcept;
|
||||
|
||||
/** Returns the timestamp of the event at a given index.
|
||||
If the index is out-of-range, this will return 0.0
|
||||
*/
|
||||
double getEventTime (int index) const;
|
||||
double getEventTime (int index) const noexcept;
|
||||
|
||||
//==============================================================================
|
||||
/** Inserts a midi message into the sequence.
|
||||
@@ -185,13 +185,13 @@ public:
|
||||
will scan the list and make sure all the note-offs in the MidiEventHolder
|
||||
structures are pointing at the correct ones.
|
||||
*/
|
||||
void updateMatchedPairs();
|
||||
void updateMatchedPairs() noexcept;
|
||||
|
||||
/** Forces a sort of the sequence.
|
||||
You may need to call this if you've manually modified the timestamps of some
|
||||
events such that the overall order now needs updating.
|
||||
*/
|
||||
void sort();
|
||||
void sort() noexcept;
|
||||
|
||||
//==============================================================================
|
||||
/** Copies all the messages for a particular midi channel to another sequence.
|
||||
@@ -224,7 +224,7 @@ public:
|
||||
/** Adds an offset to the timestamps of all events in the sequence.
|
||||
@param deltaTime the amount to add to each timestamp.
|
||||
*/
|
||||
void addTimeToMessages (double deltaTime);
|
||||
void addTimeToMessages (double deltaTime) noexcept;
|
||||
|
||||
//==============================================================================
|
||||
/** Scans through the sequence to determine the state of any midi controllers at
|
||||
|
||||
@@ -47,23 +47,28 @@ void ResamplingAudioSource::setResamplingRatio (const double samplesInPerOutputS
|
||||
ratio = jmax (0.0, samplesInPerOutputSample);
|
||||
}
|
||||
|
||||
void ResamplingAudioSource::prepareToPlay (int samplesPerBlockExpected,
|
||||
double sampleRate)
|
||||
void ResamplingAudioSource::prepareToPlay (int samplesPerBlockExpected, double sampleRate)
|
||||
{
|
||||
const SpinLock::ScopedLockType sl (ratioLock);
|
||||
|
||||
input->prepareToPlay (samplesPerBlockExpected, sampleRate);
|
||||
|
||||
buffer.setSize (numChannels, roundToInt (samplesPerBlockExpected * ratio) + 32);
|
||||
buffer.clear();
|
||||
sampsInBuffer = 0;
|
||||
bufferPos = 0;
|
||||
subSampleOffset = 0.0;
|
||||
|
||||
filterStates.calloc ((size_t) numChannels);
|
||||
srcBuffers.calloc ((size_t) numChannels);
|
||||
destBuffers.calloc ((size_t) numChannels);
|
||||
createLowPass (ratio);
|
||||
|
||||
flushBuffers();
|
||||
}
|
||||
|
||||
void ResamplingAudioSource::flushBuffers()
|
||||
{
|
||||
buffer.clear();
|
||||
bufferPos = 0;
|
||||
sampsInBuffer = 0;
|
||||
subSampleOffset = 0.0;
|
||||
resetFilters();
|
||||
}
|
||||
|
||||
@@ -225,7 +230,8 @@ void ResamplingAudioSource::setFilterCoefficients (double c1, double c2, double
|
||||
|
||||
void ResamplingAudioSource::resetFilters()
|
||||
{
|
||||
filterStates.clear ((size_t) numChannels);
|
||||
if (filterStates != nullptr)
|
||||
filterStates.clear ((size_t) numChannels);
|
||||
}
|
||||
|
||||
void ResamplingAudioSource::applyFilter (float* samples, int num, FilterState& fs)
|
||||
|
||||
@@ -66,6 +66,9 @@ public:
|
||||
*/
|
||||
double getResamplingRatio() const noexcept { return ratio; }
|
||||
|
||||
/** Clears any buffers and filters that the resampler is using. */
|
||||
void flushBuffers();
|
||||
|
||||
//==============================================================================
|
||||
void prepareToPlay (int samplesPerBlockExpected, double sampleRate) override;
|
||||
void releaseResources() override;
|
||||
|
||||
@@ -163,10 +163,7 @@ void Synthesiser::renderNextBlock (AudioSampleBuffer& outputBuffer, const MidiBu
|
||||
: numSamples;
|
||||
|
||||
if (numThisTime > 0)
|
||||
{
|
||||
for (int i = voices.size(); --i >= 0;)
|
||||
voices.getUnchecked (i)->renderNextBlock (outputBuffer, startSample, numThisTime);
|
||||
}
|
||||
renderVoices (outputBuffer, startSample, numThisTime);
|
||||
|
||||
if (useEvent)
|
||||
handleMidiEvent (m);
|
||||
@@ -176,6 +173,12 @@ void Synthesiser::renderNextBlock (AudioSampleBuffer& outputBuffer, const MidiBu
|
||||
}
|
||||
}
|
||||
|
||||
void Synthesiser::renderVoices (AudioSampleBuffer& buffer, int startSample, int numSamples)
|
||||
{
|
||||
for (int i = voices.size(); --i >= 0;)
|
||||
voices.getUnchecked (i)->renderNextBlock (buffer, startSample, numSamples);
|
||||
}
|
||||
|
||||
void Synthesiser::handleMidiEvent (const MidiMessage& m)
|
||||
{
|
||||
if (m.isNoteOn())
|
||||
@@ -184,7 +187,7 @@ void Synthesiser::handleMidiEvent (const MidiMessage& m)
|
||||
}
|
||||
else if (m.isNoteOff())
|
||||
{
|
||||
noteOff (m.getChannel(), m.getNoteNumber(), true);
|
||||
noteOff (m.getChannel(), m.getNoteNumber(), m.getFloatVelocity(), true);
|
||||
}
|
||||
else if (m.isAllNotesOff() || m.isAllSoundOff())
|
||||
{
|
||||
@@ -230,10 +233,10 @@ void Synthesiser::noteOn (const int midiChannel,
|
||||
|
||||
if (voice->getCurrentlyPlayingNote() == midiNoteNumber
|
||||
&& voice->isPlayingChannel (midiChannel))
|
||||
stopVoice (voice, true);
|
||||
stopVoice (voice, 1.0f, true);
|
||||
}
|
||||
|
||||
startVoice (findFreeVoice (sound, shouldStealNotes),
|
||||
startVoice (findFreeVoice (sound, midiChannel, midiNoteNumber, shouldStealNotes),
|
||||
sound, midiChannel, midiNoteNumber, velocity);
|
||||
}
|
||||
}
|
||||
@@ -248,7 +251,7 @@ void Synthesiser::startVoice (SynthesiserVoice* const voice,
|
||||
if (voice != nullptr && sound != nullptr)
|
||||
{
|
||||
if (voice->currentlyPlayingSound != nullptr)
|
||||
voice->stopNote (false);
|
||||
voice->stopNote (0.0f, false);
|
||||
|
||||
voice->startNote (midiNoteNumber, velocity, sound,
|
||||
lastPitchWheelValues [midiChannel - 1]);
|
||||
@@ -261,11 +264,11 @@ void Synthesiser::startVoice (SynthesiserVoice* const voice,
|
||||
}
|
||||
}
|
||||
|
||||
void Synthesiser::stopVoice (SynthesiserVoice* voice, const bool allowTailOff)
|
||||
void Synthesiser::stopVoice (SynthesiserVoice* voice, float velocity, const bool allowTailOff)
|
||||
{
|
||||
jassert (voice != nullptr);
|
||||
|
||||
voice->stopNote (allowTailOff);
|
||||
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));
|
||||
@@ -273,6 +276,7 @@ void Synthesiser::stopVoice (SynthesiserVoice* voice, const bool allowTailOff)
|
||||
|
||||
void Synthesiser::noteOff (const int midiChannel,
|
||||
const int midiNoteNumber,
|
||||
const float velocity,
|
||||
const bool allowTailOff)
|
||||
{
|
||||
const ScopedLock sl (lock);
|
||||
@@ -291,7 +295,7 @@ void Synthesiser::noteOff (const int midiChannel,
|
||||
voice->keyIsDown = false;
|
||||
|
||||
if (! (sustainPedalsDown [midiChannel] || voice->sostenutoPedalDown))
|
||||
stopVoice (voice, allowTailOff);
|
||||
stopVoice (voice, velocity, allowTailOff);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -307,7 +311,7 @@ void Synthesiser::allNotesOff (const int midiChannel, const bool allowTailOff)
|
||||
SynthesiserVoice* const voice = voices.getUnchecked (i);
|
||||
|
||||
if (midiChannel <= 0 || voice->isPlayingChannel (midiChannel))
|
||||
voice->stopNote (allowTailOff);
|
||||
voice->stopNote (1.0f, allowTailOff);
|
||||
}
|
||||
|
||||
sustainPedalsDown.clear();
|
||||
@@ -379,7 +383,7 @@ void Synthesiser::handleSustainPedal (int midiChannel, bool isDown)
|
||||
SynthesiserVoice* const voice = voices.getUnchecked (i);
|
||||
|
||||
if (voice->isPlayingChannel (midiChannel) && ! voice->keyIsDown)
|
||||
stopVoice (voice, true);
|
||||
stopVoice (voice, 1.0f, true);
|
||||
}
|
||||
|
||||
sustainPedalsDown.clearBit (midiChannel);
|
||||
@@ -400,7 +404,7 @@ void Synthesiser::handleSostenutoPedal (int midiChannel, bool isDown)
|
||||
if (isDown)
|
||||
voice->sostenutoPedalDown = true;
|
||||
else if (voice->sostenutoPedalDown)
|
||||
stopVoice (voice, true);
|
||||
stopVoice (voice, 1.0f, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -412,7 +416,9 @@ void Synthesiser::handleSoftPedal (int midiChannel, bool /*isDown*/)
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
SynthesiserVoice* Synthesiser::findFreeVoice (SynthesiserSound* soundToPlay, const bool stealIfNoneAvailable) const
|
||||
SynthesiserVoice* Synthesiser::findFreeVoice (SynthesiserSound* soundToPlay,
|
||||
int midiChannel, int midiNoteNumber,
|
||||
const bool stealIfNoneAvailable) const
|
||||
{
|
||||
const ScopedLock sl (lock);
|
||||
|
||||
@@ -425,25 +431,68 @@ SynthesiserVoice* Synthesiser::findFreeVoice (SynthesiserSound* soundToPlay, con
|
||||
}
|
||||
|
||||
if (stealIfNoneAvailable)
|
||||
return findVoiceToSteal (soundToPlay);
|
||||
return findVoiceToSteal (soundToPlay, midiChannel, midiNoteNumber);
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SynthesiserVoice* Synthesiser::findVoiceToSteal (SynthesiserSound* soundToPlay) const
|
||||
struct VoiceAgeSorter
|
||||
{
|
||||
// currently this just steals the one that's been playing the longest, but could be made a bit smarter..
|
||||
SynthesiserVoice* oldest = nullptr;
|
||||
static int compareElements (SynthesiserVoice* v1, SynthesiserVoice* v2) noexcept
|
||||
{
|
||||
return v1->wasStartedBefore (*v2) ? 1 : (v2->wasStartedBefore (*v1) ? -1 : 0);
|
||||
}
|
||||
};
|
||||
|
||||
SynthesiserVoice* Synthesiser::findVoiceToSteal (SynthesiserSound* soundToPlay,
|
||||
int /*midiChannel*/, int midiNoteNumber) const
|
||||
{
|
||||
SynthesiserVoice* bottom = nullptr;
|
||||
SynthesiserVoice* top = nullptr;
|
||||
|
||||
// this is a list of voices we can steal, sorted by how long they've been running
|
||||
Array<SynthesiserVoice*> usableVoices;
|
||||
usableVoices.ensureStorageAllocated (voices.size());
|
||||
|
||||
for (int i = 0; i < voices.size(); ++i)
|
||||
{
|
||||
SynthesiserVoice* const voice = voices.getUnchecked (i);
|
||||
|
||||
if (voice->canPlaySound (soundToPlay)
|
||||
&& (oldest == nullptr || voice->wasStartedBefore (*oldest)))
|
||||
oldest = voice;
|
||||
if (voice->canPlaySound (soundToPlay))
|
||||
{
|
||||
VoiceAgeSorter sorter;
|
||||
usableVoices.addSorted (sorter, voice);
|
||||
|
||||
const int note = voice->getCurrentlyPlayingNote();
|
||||
|
||||
if (bottom == nullptr || note < bottom->getCurrentlyPlayingNote())
|
||||
bottom = voice;
|
||||
|
||||
if (top == nullptr || note > top->getCurrentlyPlayingNote())
|
||||
top = voice;
|
||||
}
|
||||
}
|
||||
|
||||
jassert (oldest != nullptr);
|
||||
return oldest;
|
||||
jassert (bottom != nullptr && top != nullptr);
|
||||
|
||||
// The oldest note that's playing with the target pitch playing is ideal..
|
||||
for (int i = 0; i < usableVoices.size(); ++i)
|
||||
{
|
||||
SynthesiserVoice* const voice = usableVoices.getUnchecked (i);
|
||||
|
||||
if (voice->getCurrentlyPlayingNote() == midiNoteNumber)
|
||||
return voice;
|
||||
}
|
||||
|
||||
// ..otherwise, look for the oldest note that isn't the top or bottom note..
|
||||
for (int i = 0; i < usableVoices.size(); ++i)
|
||||
{
|
||||
SynthesiserVoice* const voice = usableVoices.getUnchecked (i);
|
||||
|
||||
if (voice != bottom && voice != top)
|
||||
return voice;
|
||||
}
|
||||
|
||||
// ..otherwise, there's only one or two voices to choose from - we'll return the top one..
|
||||
return top;
|
||||
}
|
||||
|
||||
@@ -55,14 +55,14 @@ public:
|
||||
The Synthesiser will use this information when deciding which sounds to trigger
|
||||
for a given note.
|
||||
*/
|
||||
virtual bool appliesToNote (const int midiNoteNumber) = 0;
|
||||
virtual bool appliesToNote (int midiNoteNumber) = 0;
|
||||
|
||||
/** Returns true if the sound should be triggered by midi events on a given channel.
|
||||
|
||||
The Synthesiser will use this information when deciding which sounds to trigger
|
||||
for a given note.
|
||||
*/
|
||||
virtual bool appliesToChannel (const int midiChannel) = 0;
|
||||
virtual bool appliesToChannel (int midiChannel) = 0;
|
||||
|
||||
/** The class is reference-counted, so this is a handy pointer class for it. */
|
||||
typedef ReferenceCountedObjectPtr<SynthesiserSound> Ptr;
|
||||
@@ -127,6 +127,8 @@ public:
|
||||
|
||||
This will be called during the rendering callback, so must be fast and thread-safe.
|
||||
|
||||
The velocity indicates how quickly the note was released - 0 is slowly, 1 is quickly.
|
||||
|
||||
If allowTailOff is false or the voice doesn't want to tail-off, then it must stop all
|
||||
sound immediately, and must call clearCurrentNote() to reset the state of this voice
|
||||
and allow the synth to reassign it another sound.
|
||||
@@ -136,7 +138,7 @@ public:
|
||||
finishes playing (during the rendering callback), it must make sure that it calls
|
||||
clearCurrentNote().
|
||||
*/
|
||||
virtual void stopNote (bool allowTailOff) = 0;
|
||||
virtual void stopNote (float velocity, bool allowTailOff) = 0;
|
||||
|
||||
/** Called to let the voice know that the pitch wheel has been moved.
|
||||
This will be called during the rendering callback, so must be fast and thread-safe.
|
||||
@@ -173,13 +175,6 @@ public:
|
||||
int startSample,
|
||||
int numSamples) = 0;
|
||||
|
||||
/** Returns true if the voice is currently playing a sound which is mapped to the given
|
||||
midi channel.
|
||||
|
||||
If it's not currently playing, this will return false.
|
||||
*/
|
||||
bool isPlayingChannel (int midiChannel) const;
|
||||
|
||||
/** Changes the voice's reference sample rate.
|
||||
|
||||
The rate is set so that subclasses know the output rate and can set their pitch
|
||||
@@ -188,7 +183,19 @@ public:
|
||||
This method is called by the synth, and subclasses can access the current rate with
|
||||
the currentSampleRate member.
|
||||
*/
|
||||
void setCurrentPlaybackSampleRate (double newRate);
|
||||
virtual void setCurrentPlaybackSampleRate (double newRate);
|
||||
|
||||
/** 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.
|
||||
*/
|
||||
double getSampleRate() const noexcept { return currentSampleRate; }
|
||||
|
||||
/** Returns true if the voice is currently playing a sound which is mapped to the given
|
||||
midi channel.
|
||||
|
||||
If it's not currently playing, this will return false.
|
||||
*/
|
||||
bool isPlayingChannel (int midiChannel) const;
|
||||
|
||||
/** Returns true if the key that triggered this voice is still held down.
|
||||
Note that the voice may still be playing after the key was released (e.g because the
|
||||
@@ -203,13 +210,6 @@ public:
|
||||
bool wasStartedBefore (const SynthesiserVoice& other) const noexcept;
|
||||
|
||||
protected:
|
||||
//==============================================================================
|
||||
/** Returns the current target sample rate at which rendering is being done.
|
||||
|
||||
This is available for subclasses so they can pitch things correctly.
|
||||
*/
|
||||
double getSampleRate() const { return currentSampleRate; }
|
||||
|
||||
/** Resets the state of this voice after a sound has finished playing.
|
||||
|
||||
The subclass must call this when it finishes playing a note and becomes available
|
||||
@@ -235,6 +235,11 @@ private:
|
||||
SynthesiserSound::Ptr currentlyPlayingSound;
|
||||
bool keyIsDown, sostenutoPedalDown;
|
||||
|
||||
#if JUCE_CATCH_DEPRECATED_CODE_MISUSE
|
||||
// Note the new parameters for this method.
|
||||
virtual int stopNote (bool) { return 0; }
|
||||
#endif
|
||||
|
||||
JUCE_LEAK_DETECTOR (SynthesiserVoice)
|
||||
};
|
||||
|
||||
@@ -268,8 +273,7 @@ class JUCE_API Synthesiser
|
||||
public:
|
||||
//==============================================================================
|
||||
/** Creates a new synthesiser.
|
||||
|
||||
You'll need to add some sounds and voices before it'll make any sound..
|
||||
You'll need to add some sounds and voices before it'll make any sound.
|
||||
*/
|
||||
Synthesiser();
|
||||
|
||||
@@ -365,6 +369,7 @@ public:
|
||||
*/
|
||||
virtual void noteOff (int midiChannel,
|
||||
int midiNoteNumber,
|
||||
float velocity,
|
||||
bool allowTailOff);
|
||||
|
||||
/** Turns off all notes.
|
||||
@@ -444,7 +449,7 @@ public:
|
||||
This value is propagated to the voices so that they can use it to render the correct
|
||||
pitches.
|
||||
*/
|
||||
void setCurrentPlaybackSampleRate (double sampleRate);
|
||||
virtual void setCurrentPlaybackSampleRate (double sampleRate);
|
||||
|
||||
/** Creates the next block of audio output.
|
||||
|
||||
@@ -463,6 +468,11 @@ public:
|
||||
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.
|
||||
*/
|
||||
double getSampleRate() const noexcept { return sampleRate; }
|
||||
|
||||
protected:
|
||||
//==============================================================================
|
||||
/** This is used to control access to the rendering callback and the note trigger methods. */
|
||||
@@ -474,21 +484,34 @@ protected:
|
||||
/** The last pitch-wheel values for each midi channel. */
|
||||
int lastPitchWheelValues [16];
|
||||
|
||||
/** Searches through the voices to find one that's not currently playing, and which
|
||||
can play the given sound.
|
||||
/** Renders the voices for the given range.
|
||||
By default this just calls renderNextBlock() on each voice, but you may need
|
||||
to override it to handle custom cases.
|
||||
*/
|
||||
virtual void renderVoices (AudioSampleBuffer& outputAudio,
|
||||
int startSample, int numSamples);
|
||||
|
||||
/** Searches through the voices to find one that's not currently playing, and
|
||||
which can play the given sound.
|
||||
|
||||
Returns nullptr if all voices are busy and stealing isn't enabled.
|
||||
|
||||
This can be overridden to implement custom voice-stealing algorithms.
|
||||
To implement a custom note-stealing algorithm, you can either override this
|
||||
method, or (preferably) override findVoiceToSteal().
|
||||
*/
|
||||
virtual SynthesiserVoice* findFreeVoice (SynthesiserSound* soundToPlay,
|
||||
const bool stealIfNoneAvailable) const;
|
||||
int midiChannel,
|
||||
int midiNoteNumber,
|
||||
bool stealIfNoneAvailable) const;
|
||||
|
||||
/** Chooses a voice that is most suitable for being re-used.
|
||||
The default method returns the one that has been playing for the longest, but
|
||||
you may want to override this and do something more cunning instead.
|
||||
The default method will attempt to find the oldest voice that isn't the
|
||||
bottom or top note being played. If that's not suitable for your synth,
|
||||
you can override this method and do something more cunning instead.
|
||||
*/
|
||||
virtual SynthesiserVoice* findVoiceToSteal (SynthesiserSound* soundToPlay) const;
|
||||
virtual SynthesiserVoice* findVoiceToSteal (SynthesiserSound* soundToPlay,
|
||||
int midiChannel,
|
||||
int midiNoteNumber) const;
|
||||
|
||||
/** Starts a specified voice playing a particular sound.
|
||||
|
||||
@@ -511,11 +534,14 @@ private:
|
||||
bool shouldStealNotes;
|
||||
BigInteger sustainPedalsDown;
|
||||
|
||||
void stopVoice (SynthesiserVoice*, bool allowTailOff);
|
||||
void stopVoice (SynthesiserVoice*, float velocity, bool allowTailOff);
|
||||
|
||||
#if JUCE_CATCH_DEPRECATED_CODE_MISUSE
|
||||
// Note the new parameters for this method.
|
||||
// Note the new parameters for these methods.
|
||||
virtual int findFreeVoice (const bool) const { return 0; }
|
||||
virtual int noteOff (int, int, int) { return 0; }
|
||||
virtual int findFreeVoice (SynthesiserSound*, const bool) { return 0; }
|
||||
virtual int findVoiceToSteal (SynthesiserSound*) const { return 0; }
|
||||
#endif
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Synthesiser)
|
||||
|
||||
@@ -859,8 +859,11 @@ void AudioDeviceManager::addMidiInputCallback (const String& name, MidiInputCall
|
||||
if (name.isEmpty() || isMidiInputEnabled (name))
|
||||
{
|
||||
const ScopedLock sl (midiCallbackLock);
|
||||
midiCallbacks.add (callbackToAdd);
|
||||
midiCallbackDevices.add (name);
|
||||
|
||||
MidiCallbackInfo mc;
|
||||
mc.deviceName = name;
|
||||
mc.callback = callbackToAdd;
|
||||
midiCallbacks.add (mc);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -868,11 +871,12 @@ void AudioDeviceManager::removeMidiInputCallback (const String& name, MidiInputC
|
||||
{
|
||||
for (int i = midiCallbacks.size(); --i >= 0;)
|
||||
{
|
||||
if (midiCallbackDevices[i] == name && midiCallbacks.getUnchecked(i) == callbackToRemove)
|
||||
const MidiCallbackInfo& mc = midiCallbacks.getReference(i);
|
||||
|
||||
if (mc.callback == callbackToRemove && mc.deviceName == name)
|
||||
{
|
||||
const ScopedLock sl (midiCallbackLock);
|
||||
midiCallbacks.remove (i);
|
||||
midiCallbackDevices.remove (i);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -881,16 +885,14 @@ void AudioDeviceManager::handleIncomingMidiMessageInt (MidiInput* source, const
|
||||
{
|
||||
if (! message.isActiveSense())
|
||||
{
|
||||
const bool isDefaultSource = (source == nullptr || source == enabledMidiInputs.getFirst());
|
||||
|
||||
const ScopedLock sl (midiCallbackLock);
|
||||
|
||||
for (int i = midiCallbackDevices.size(); --i >= 0;)
|
||||
for (int i = 0; i < midiCallbacks.size(); ++i)
|
||||
{
|
||||
const String name (midiCallbackDevices[i]);
|
||||
const MidiCallbackInfo& mc = midiCallbacks.getReference(i);
|
||||
|
||||
if ((isDefaultSource && name.isEmpty()) || (name.isNotEmpty() && name == source->getName()))
|
||||
midiCallbacks.getUnchecked(i)->handleIncomingMidiMessage (source, message);
|
||||
if (mc.deviceName.isEmpty() || mc.deviceName == source->getName())
|
||||
mc.callback->handleIncomingMidiMessage (source, message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -209,10 +209,9 @@ public:
|
||||
|
||||
//==============================================================================
|
||||
/** Returns the current device properties that are in use.
|
||||
|
||||
@see setAudioDeviceSetup
|
||||
*/
|
||||
void getAudioDeviceSetup (AudioDeviceSetup& setup);
|
||||
void getAudioDeviceSetup (AudioDeviceSetup& result);
|
||||
|
||||
/** Changes the current device or its settings.
|
||||
|
||||
@@ -261,9 +260,7 @@ public:
|
||||
void setCurrentAudioDeviceType (const String& type,
|
||||
bool treatAsChosenDevice);
|
||||
|
||||
|
||||
/** Closes the currently-open device.
|
||||
|
||||
You can call restartLastAudioDevice() later to reopen it in the same state
|
||||
that it was just in.
|
||||
*/
|
||||
@@ -305,8 +302,8 @@ public:
|
||||
|
||||
//==============================================================================
|
||||
/** Returns the average proportion of available CPU being spent inside the audio callbacks.
|
||||
|
||||
Returns a value between 0 and 1.0
|
||||
@returns A value between 0 and 1.0 to indicate the approximate proportion of CPU
|
||||
time spent in the callbacks.
|
||||
*/
|
||||
double getCpuUsage() const;
|
||||
|
||||
@@ -333,16 +330,16 @@ public:
|
||||
void setMidiInputEnabled (const String& midiInputDeviceName, bool enabled);
|
||||
|
||||
/** Returns true if a given midi input device is being used.
|
||||
|
||||
@see setMidiInputEnabled
|
||||
*/
|
||||
bool isMidiInputEnabled (const String& midiInputDeviceName) const;
|
||||
|
||||
/** Registers a listener for callbacks when midi events arrive from a midi input.
|
||||
|
||||
The device name can be empty to indicate that it wants events from whatever the
|
||||
current "default" device is. Or it can be the name of one of the midi input devices
|
||||
(see MidiInput::getDevices() for the names).
|
||||
The device name can be empty to indicate that it wants to receive all incoming
|
||||
events from all the enabled MIDI inputs. Or it can be the name of one of the
|
||||
MIDI input devices if it just wants the events from that device. (see
|
||||
MidiInput::getDevices() for the list of device names).
|
||||
|
||||
Only devices which are enabled (see the setMidiInputEnabled() method) will have their
|
||||
events forwarded on to listeners.
|
||||
@@ -350,8 +347,7 @@ public:
|
||||
void addMidiInputCallback (const String& midiInputDeviceName,
|
||||
MidiInputCallback* callback);
|
||||
|
||||
/** Removes a listener that was previously registered with addMidiInputCallback().
|
||||
*/
|
||||
/** Removes a listener that was previously registered with addMidiInputCallback(). */
|
||||
void removeMidiInputCallback (const String& midiInputDeviceName,
|
||||
MidiInputCallback* callback);
|
||||
|
||||
@@ -371,22 +367,17 @@ public:
|
||||
void setDefaultMidiOutput (const String& deviceName);
|
||||
|
||||
/** Returns the name of the default midi output.
|
||||
|
||||
@see setDefaultMidiOutput, getDefaultMidiOutput
|
||||
*/
|
||||
String getDefaultMidiOutputName() const { return defaultMidiOutputName; }
|
||||
const String& getDefaultMidiOutputName() const noexcept { return defaultMidiOutputName; }
|
||||
|
||||
/** Returns the current default midi output device.
|
||||
|
||||
If no device has been selected, or the device can't be opened, this will
|
||||
return 0.
|
||||
|
||||
If no device has been selected, or the device can't be opened, this will return nullptr.
|
||||
@see getDefaultMidiOutputName
|
||||
*/
|
||||
MidiOutput* getDefaultMidiOutput() const noexcept { return defaultMidiOutput; }
|
||||
|
||||
/** Returns a list of the types of device supported.
|
||||
*/
|
||||
/** Returns a list of the types of device supported. */
|
||||
const OwnedArray<AudioIODeviceType>& getAvailableDeviceTypes();
|
||||
|
||||
//==============================================================================
|
||||
@@ -429,9 +420,7 @@ public:
|
||||
void enableInputLevelMeasurement (bool enableMeasurement);
|
||||
|
||||
/** Returns the current input level.
|
||||
|
||||
To use this, you must first enable it by calling enableInputLevelMeasurement().
|
||||
|
||||
See enableInputLevelMeasurement() for more info.
|
||||
*/
|
||||
double getCurrentInputLevel() const;
|
||||
@@ -468,10 +457,16 @@ private:
|
||||
int testSoundPosition;
|
||||
AudioSampleBuffer tempBuffer;
|
||||
|
||||
struct MidiCallbackInfo
|
||||
{
|
||||
String deviceName;
|
||||
MidiInputCallback* callback;
|
||||
};
|
||||
|
||||
StringArray midiInsFromXml;
|
||||
OwnedArray<MidiInput> enabledMidiInputs;
|
||||
Array<MidiInputCallback*> midiCallbacks;
|
||||
StringArray midiCallbackDevices;
|
||||
Array<MidiCallbackInfo> midiCallbacks;
|
||||
|
||||
String defaultMidiOutputName;
|
||||
ScopedPointer<MidiOutput> defaultMidiOutput;
|
||||
CriticalSection audioCallbackLock, midiCallbackLock;
|
||||
|
||||
@@ -22,20 +22,16 @@
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
AudioIODevice::AudioIODevice (const String& deviceName, const String& typeName_)
|
||||
: name (deviceName),
|
||||
typeName (typeName_)
|
||||
AudioIODevice::AudioIODevice (const String& deviceName, const String& deviceTypeName)
|
||||
: name (deviceName), typeName (deviceTypeName)
|
||||
{
|
||||
}
|
||||
|
||||
AudioIODevice::~AudioIODevice()
|
||||
{
|
||||
}
|
||||
AudioIODevice::~AudioIODevice() {}
|
||||
|
||||
bool AudioIODevice::hasControlPanel() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
void AudioIODeviceCallback::audioDeviceError (const String&) {}
|
||||
bool AudioIODevice::setAudioPreprocessingEnabled (bool) { return false; }
|
||||
bool AudioIODevice::hasControlPanel() const { return false; }
|
||||
|
||||
bool AudioIODevice::showControlPanel()
|
||||
{
|
||||
@@ -43,6 +39,3 @@ bool AudioIODevice::showControlPanel()
|
||||
// their hasControlPanel() method.
|
||||
return false;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void AudioIODeviceCallback::audioDeviceError (const String&) {}
|
||||
|
||||
@@ -289,6 +289,11 @@ public:
|
||||
*/
|
||||
virtual bool showControlPanel();
|
||||
|
||||
/** On devices which support it, this allows automatic gain control or other
|
||||
mic processing to be disabled.
|
||||
If the device doesn't support this operation, it'll return false.
|
||||
*/
|
||||
virtual bool setAudioPreprocessingEnabled (bool shouldBeEnabled);
|
||||
|
||||
//==============================================================================
|
||||
protected:
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
method. Each of the objects returned can then be used to list the available
|
||||
devices of that type. E.g.
|
||||
@code
|
||||
OwnedArray <AudioIODeviceType> types;
|
||||
OwnedArray<AudioIODeviceType> types;
|
||||
myAudioDeviceManager.createAudioDeviceTypes (types);
|
||||
|
||||
for (int i = 0; i < types.size(); ++i)
|
||||
|
||||
@@ -125,6 +125,7 @@
|
||||
#if JUCE_USE_ANDROID_OPENSLES
|
||||
#include <SLES/OpenSLES.h>
|
||||
#include <SLES/OpenSLES_Android.h>
|
||||
#include <SLES/OpenSLES_AndroidConfiguration.h>
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"id": "juce_audio_devices",
|
||||
"name": "JUCE audio and midi I/O device classes",
|
||||
"version": "3.0.5",
|
||||
"version": "3.0.8",
|
||||
"description": "Classes to play and record from audio and midi i/o devices.",
|
||||
"website": "http://www.juce.com/juce",
|
||||
"license": "GPL/Commercial",
|
||||
|
||||
@@ -80,7 +80,7 @@ public:
|
||||
|
||||
Array<double> getAvailableSampleRates() override
|
||||
{
|
||||
static const double rates[] = { 8000.0, 16000.0, 32000.0, 44100.0, 48000.0 };
|
||||
static const double rates[] = { 8000.0, 16000.0, 32000.0, 44100.0, 48000.0 };
|
||||
return Array<double> (rates, numElementsInArray (rates));
|
||||
}
|
||||
|
||||
@@ -165,6 +165,33 @@ public:
|
||||
oldCallback->audioDeviceStopped();
|
||||
}
|
||||
|
||||
bool setAudioPreprocessingEnabled (bool enable) override
|
||||
{
|
||||
return recorder != nullptr && recorder->setAudioPreprocessingEnabled (enable);
|
||||
}
|
||||
|
||||
private:
|
||||
//==================================================================================================
|
||||
CriticalSection callbackLock;
|
||||
AudioIODeviceCallback* callback;
|
||||
int actualBufferSize, sampleRate;
|
||||
int inputLatency, outputLatency;
|
||||
bool deviceOpen;
|
||||
String lastError;
|
||||
BigInteger activeOutputChans, activeInputChans;
|
||||
int numInputChannels, numOutputChannels;
|
||||
AudioSampleBuffer inputBuffer, outputBuffer;
|
||||
struct Player;
|
||||
struct Recorder;
|
||||
|
||||
AudioIODeviceCallback* setCallback (AudioIODeviceCallback* const newCallback)
|
||||
{
|
||||
const ScopedLock sl (callbackLock);
|
||||
AudioIODeviceCallback* const oldCallback = callback;
|
||||
callback = newCallback;
|
||||
return oldCallback;
|
||||
}
|
||||
|
||||
void run() override
|
||||
{
|
||||
if (recorder != nullptr) recorder->start();
|
||||
@@ -190,28 +217,6 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
//==================================================================================================
|
||||
CriticalSection callbackLock;
|
||||
AudioIODeviceCallback* callback;
|
||||
int actualBufferSize, sampleRate;
|
||||
int inputLatency, outputLatency;
|
||||
bool deviceOpen;
|
||||
String lastError;
|
||||
BigInteger activeOutputChans, activeInputChans;
|
||||
int numInputChannels, numOutputChannels;
|
||||
AudioSampleBuffer inputBuffer, outputBuffer;
|
||||
struct Player;
|
||||
struct Recorder;
|
||||
|
||||
AudioIODeviceCallback* setCallback (AudioIODeviceCallback* const newCallback)
|
||||
{
|
||||
const ScopedLock sl (callbackLock);
|
||||
AudioIODeviceCallback* const oldCallback = callback;
|
||||
callback = newCallback;
|
||||
return oldCallback;
|
||||
}
|
||||
|
||||
//==================================================================================================
|
||||
struct Engine
|
||||
{
|
||||
@@ -230,6 +235,7 @@ private:
|
||||
SL_IID_ANDROIDSIMPLEBUFFERQUEUE = (SLInterfaceID*) library.getFunction ("SL_IID_ANDROIDSIMPLEBUFFERQUEUE");
|
||||
SL_IID_PLAY = (SLInterfaceID*) library.getFunction ("SL_IID_PLAY");
|
||||
SL_IID_RECORD = (SLInterfaceID*) library.getFunction ("SL_IID_RECORD");
|
||||
SL_IID_ANDROIDCONFIGURATION = (SLInterfaceID*) library.getFunction ("SL_IID_ANDROIDCONFIGURATION");
|
||||
|
||||
check ((*engineObject)->Realize (engineObject, SL_BOOLEAN_FALSE));
|
||||
check ((*engineObject)->GetInterface (engineObject, *SL_IID_ENGINE, &engineInterface));
|
||||
@@ -271,6 +277,7 @@ private:
|
||||
SLInterfaceID* SL_IID_ANDROIDSIMPLEBUFFERQUEUE;
|
||||
SLInterfaceID* SL_IID_PLAY;
|
||||
SLInterfaceID* SL_IID_RECORD;
|
||||
SLInterfaceID* SL_IID_ANDROIDCONFIGURATION;
|
||||
|
||||
private:
|
||||
DynamicLibrary library;
|
||||
@@ -334,8 +341,8 @@ private:
|
||||
SLDataFormat_PCM pcmFormat =
|
||||
{
|
||||
SL_DATAFORMAT_PCM,
|
||||
numChannels,
|
||||
sampleRate * 1000, // (sample rate units are millihertz)
|
||||
(SLuint32) numChannels,
|
||||
(SLuint32) (sampleRate * 1000), // (sample rate units are millihertz)
|
||||
SL_PCMSAMPLEFORMAT_FIXED_16,
|
||||
SL_PCMSAMPLEFORMAT_FIXED_16,
|
||||
SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT,
|
||||
@@ -434,7 +441,8 @@ private:
|
||||
struct Recorder
|
||||
{
|
||||
Recorder (int numChannels, int sampleRate, Engine& engine)
|
||||
: recorderObject (nullptr), recorderRecord (nullptr), recorderBufferQueue (nullptr),
|
||||
: recorderObject (nullptr), recorderRecord (nullptr),
|
||||
recorderBufferQueue (nullptr), configObject (nullptr),
|
||||
bufferList (numChannels)
|
||||
{
|
||||
jassert (numChannels == 1); // STEREO doesn't always work!!
|
||||
@@ -442,8 +450,8 @@ private:
|
||||
SLDataFormat_PCM pcmFormat =
|
||||
{
|
||||
SL_DATAFORMAT_PCM,
|
||||
numChannels,
|
||||
sampleRate * 1000, // (sample rate units are millihertz)
|
||||
(SLuint32) numChannels,
|
||||
(SLuint32) (sampleRate * 1000), // (sample rate units are millihertz)
|
||||
SL_PCMSAMPLEFORMAT_FIXED_16,
|
||||
SL_PCMSAMPLEFORMAT_FIXED_16,
|
||||
(numChannels == 1) ? SL_SPEAKER_FRONT_CENTER : (SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT),
|
||||
@@ -466,6 +474,7 @@ private:
|
||||
{
|
||||
check ((*recorderObject)->GetInterface (recorderObject, *engine.SL_IID_RECORD, &recorderRecord));
|
||||
check ((*recorderObject)->GetInterface (recorderObject, *engine.SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &recorderBufferQueue));
|
||||
check ((*recorderObject)->GetInterface (recorderObject, *engine.SL_IID_ANDROIDCONFIGURATION, &configObject));
|
||||
check ((*recorderBufferQueue)->RegisterCallback (recorderBufferQueue, staticCallback, this));
|
||||
check ((*recorderRecord)->SetRecordState (recorderRecord, SL_RECORDSTATE_STOPPED));
|
||||
|
||||
@@ -532,10 +541,20 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
bool setAudioPreprocessingEnabled (bool enable)
|
||||
{
|
||||
SLuint32 mode = enable ? SL_ANDROID_RECORDING_PRESET_GENERIC
|
||||
: SL_ANDROID_RECORDING_PRESET_VOICE_RECOGNITION;
|
||||
|
||||
return configObject != nullptr
|
||||
&& check ((*configObject)->SetConfiguration (configObject, SL_ANDROID_KEY_RECORDING_PRESET, &mode, sizeof (mode)));
|
||||
}
|
||||
|
||||
private:
|
||||
SLObjectItf recorderObject;
|
||||
SLRecordItf recorderRecord;
|
||||
SLAndroidSimpleBufferQueueItf recorderBufferQueue;
|
||||
SLAndroidConfigurationItf configObject;
|
||||
|
||||
BufferList bufferList;
|
||||
|
||||
|
||||
@@ -67,7 +67,12 @@ public:
|
||||
return s;
|
||||
}
|
||||
|
||||
Array<double> getAvailableSampleRates() override { return sampleRates; }
|
||||
Array<double> getAvailableSampleRates() override
|
||||
{
|
||||
// can't find a good way to actually ask the device for which of these it supports..
|
||||
static const double rates[] = { 8000.0, 16000.0, 22050.0, 32000.0, 44100.0, 48000.0 };
|
||||
return Array<double> (rates, numElementsInArray (rates));
|
||||
}
|
||||
|
||||
Array<int> getAvailableBufferSizes() override
|
||||
{
|
||||
@@ -79,7 +84,7 @@ public:
|
||||
return r;
|
||||
}
|
||||
|
||||
int getDefaultBufferSize() override { return 1024; }
|
||||
int getDefaultBufferSize() override { return 1024; }
|
||||
|
||||
String open (const BigInteger& inputChannelsWanted,
|
||||
const BigInteger& outputChannelsWanted,
|
||||
@@ -117,10 +122,9 @@ public:
|
||||
AudioSessionAddPropertyListener (kAudioSessionProperty_AudioRouteChange, routingChangedStatic, this);
|
||||
|
||||
fixAudioRouteIfSetToReceiver();
|
||||
updateDeviceInfo();
|
||||
|
||||
setSessionFloat64Property (kAudioSessionProperty_PreferredHardwareSampleRate, targetSampleRate);
|
||||
updateSampleRates();
|
||||
updateDeviceInfo();
|
||||
|
||||
setSessionFloat32Property (kAudioSessionProperty_PreferredHardwareIOBufferDuration, preferredBufferSize / sampleRate);
|
||||
updateCurrentBufferSize();
|
||||
@@ -162,8 +166,15 @@ public:
|
||||
BigInteger getActiveOutputChannels() const override { return activeOutputChans; }
|
||||
BigInteger getActiveInputChannels() const override { return activeInputChans; }
|
||||
|
||||
int getOutputLatencyInSamples() override { return 0; } //xxx
|
||||
int getInputLatencyInSamples() override { return 0; } //xxx
|
||||
int getOutputLatencyInSamples() override { return getLatency (kAudioSessionProperty_CurrentHardwareOutputLatency); }
|
||||
int getInputLatencyInSamples() override { return getLatency (kAudioSessionProperty_CurrentHardwareInputLatency); }
|
||||
|
||||
int getLatency (AudioSessionPropertyID propID)
|
||||
{
|
||||
Float32 latency = 0;
|
||||
getSessionProperty (propID, latency);
|
||||
return roundToInt (latency * getCurrentSampleRate());
|
||||
}
|
||||
|
||||
void start (AudioIODeviceCallback* newCallback) override
|
||||
{
|
||||
@@ -197,11 +208,16 @@ public:
|
||||
bool isPlaying() override { return isRunning && callback != nullptr; }
|
||||
String getLastError() override { return lastError; }
|
||||
|
||||
bool setAudioPreprocessingEnabled (bool enable) override
|
||||
{
|
||||
return setSessionUInt32Property (kAudioSessionProperty_Mode, enable ? kAudioSessionMode_Default
|
||||
: kAudioSessionMode_Measurement);
|
||||
}
|
||||
|
||||
private:
|
||||
//==================================================================================================
|
||||
CriticalSection callbackLock;
|
||||
Float64 sampleRate;
|
||||
Array<Float64> sampleRates;
|
||||
int numInputChannels, numOutputChannels;
|
||||
int preferredBufferSize, actualBufferSize;
|
||||
bool isRunning;
|
||||
@@ -322,38 +338,6 @@ private:
|
||||
getSessionProperty (kAudioSessionProperty_AudioInputAvailable, audioInputIsAvailable);
|
||||
}
|
||||
|
||||
void updateSampleRates()
|
||||
{
|
||||
getSessionProperty (kAudioSessionProperty_CurrentHardwareSampleRate, sampleRate);
|
||||
|
||||
sampleRates.clear();
|
||||
sampleRates.add (sampleRate);
|
||||
|
||||
const int commonSampleRates[] = { 8000, 16000, 22050, 32000, 44100, 48000 };
|
||||
|
||||
for (int i = 0; i < numElementsInArray (commonSampleRates); ++i)
|
||||
{
|
||||
Float64 rate = (Float64) commonSampleRates[i];
|
||||
|
||||
if (rate != sampleRate)
|
||||
{
|
||||
setSessionFloat64Property (kAudioSessionProperty_PreferredHardwareSampleRate, rate);
|
||||
|
||||
Float64 actualSampleRate = 0.0;
|
||||
getSessionProperty (kAudioSessionProperty_CurrentHardwareSampleRate, actualSampleRate);
|
||||
|
||||
if (actualSampleRate == rate)
|
||||
sampleRates.add (actualSampleRate);
|
||||
}
|
||||
}
|
||||
|
||||
DefaultElementComparator<Float64> comparator;
|
||||
sampleRates.sort (comparator);
|
||||
|
||||
setSessionFloat64Property (kAudioSessionProperty_PreferredHardwareSampleRate, sampleRate);
|
||||
getSessionProperty (kAudioSessionProperty_CurrentHardwareSampleRate, sampleRate);
|
||||
}
|
||||
|
||||
void updateCurrentBufferSize()
|
||||
{
|
||||
Float32 bufferDuration = sampleRate > 0 ? (Float32) (preferredBufferSize / sampleRate) : 0.0f;
|
||||
@@ -455,12 +439,12 @@ private:
|
||||
static OSStatus processStatic (void* client, AudioUnitRenderActionFlags* flags, const AudioTimeStamp* time,
|
||||
UInt32 /*busNumber*/, UInt32 numFrames, AudioBufferList* data)
|
||||
{
|
||||
return static_cast <iOSAudioIODevice*> (client)->process (flags, time, numFrames, data);
|
||||
return static_cast<iOSAudioIODevice*> (client)->process (flags, time, numFrames, data);
|
||||
}
|
||||
|
||||
static void routingChangedStatic (void* client, AudioSessionPropertyID, UInt32 /*inDataSize*/, const void* propertyValue)
|
||||
{
|
||||
static_cast <iOSAudioIODevice*> (client)->routingChanged (propertyValue);
|
||||
static_cast<iOSAudioIODevice*> (client)->routingChanged (propertyValue);
|
||||
}
|
||||
|
||||
//==================================================================================================
|
||||
@@ -552,9 +536,9 @@ private:
|
||||
return AudioSessionGetProperty (propID, &valueSize, &result);
|
||||
}
|
||||
|
||||
static void setSessionUInt32Property (AudioSessionPropertyID propID, UInt32 v) noexcept { AudioSessionSetProperty (propID, sizeof (v), &v); }
|
||||
static void setSessionFloat32Property (AudioSessionPropertyID propID, Float32 v) noexcept { AudioSessionSetProperty (propID, sizeof (v), &v); }
|
||||
static void setSessionFloat64Property (AudioSessionPropertyID propID, Float64 v) noexcept { AudioSessionSetProperty (propID, sizeof (v), &v); }
|
||||
static bool setSessionUInt32Property (AudioSessionPropertyID propID, UInt32 v) noexcept { return AudioSessionSetProperty (propID, sizeof (v), &v) == kAudioSessionNoError; }
|
||||
static bool setSessionFloat32Property (AudioSessionPropertyID propID, Float32 v) noexcept { return AudioSessionSetProperty (propID, sizeof (v), &v) == kAudioSessionNoError; }
|
||||
static bool setSessionFloat64Property (AudioSessionPropertyID propID, Float64 v) noexcept { return AudioSessionSetProperty (propID, sizeof (v), &v) == kAudioSessionNoError; }
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE (iOSAudioIODevice)
|
||||
};
|
||||
|
||||
@@ -41,7 +41,7 @@ namespace
|
||||
return err;
|
||||
}
|
||||
#else
|
||||
#define JUCE_ALSA_LOG(x)
|
||||
#define JUCE_ALSA_LOG(x) {}
|
||||
#define JUCE_CHECKED_RESULT(x) (x)
|
||||
#endif
|
||||
|
||||
|
||||
@@ -144,6 +144,7 @@ public:
|
||||
: owner (d),
|
||||
inputLatency (0),
|
||||
outputLatency (0),
|
||||
bitDepth (32),
|
||||
callback (nullptr),
|
||||
#if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5
|
||||
audioProcID (0),
|
||||
@@ -232,7 +233,7 @@ public:
|
||||
size = sizeof (nameNSString);
|
||||
|
||||
pa.mSelector = kAudioObjectPropertyElementName;
|
||||
pa.mElement = chanNum + 1;
|
||||
pa.mElement = (AudioObjectPropertyElement) chanNum + 1;
|
||||
|
||||
if (AudioObjectGetPropertyData (deviceID, &pa, 0, nullptr, &size, &nameNSString) == noErr)
|
||||
{
|
||||
@@ -352,6 +353,22 @@ public:
|
||||
return (int) lat;
|
||||
}
|
||||
|
||||
int getBitDepthFromDevice (AudioObjectPropertyScope scope) const
|
||||
{
|
||||
AudioObjectPropertyAddress pa;
|
||||
pa.mElement = kAudioObjectPropertyElementMaster;
|
||||
pa.mSelector = kAudioStreamPropertyPhysicalFormat;
|
||||
pa.mScope = scope;
|
||||
|
||||
AudioStreamBasicDescription asbd;
|
||||
UInt32 size = sizeof (asbd);
|
||||
|
||||
if (OK (AudioObjectGetPropertyData (deviceID, &pa, 0, nullptr, &size, &asbd)))
|
||||
return (int) asbd.mBitsPerChannel;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void updateDetailsFromDevice()
|
||||
{
|
||||
stopTimer();
|
||||
@@ -377,7 +394,7 @@ public:
|
||||
if (OK (AudioObjectGetPropertyData (deviceID, &pa, 0, nullptr, &size, &sr)))
|
||||
sampleRate = sr;
|
||||
|
||||
UInt32 framesPerBuf = bufferSize;
|
||||
UInt32 framesPerBuf = (UInt32) bufferSize;
|
||||
size = sizeof (framesPerBuf);
|
||||
pa.mSelector = kAudioDevicePropertyBufferFrameSize;
|
||||
AudioObjectGetPropertyData (deviceID, &pa, 0, nullptr, &size, &framesPerBuf);
|
||||
@@ -392,6 +409,13 @@ public:
|
||||
StringArray newInNames (getChannelInfo (true, newInChans));
|
||||
StringArray newOutNames (getChannelInfo (false, newOutChans));
|
||||
|
||||
const int inputBitDepth = getBitDepthFromDevice (kAudioDevicePropertyScopeInput);
|
||||
const int outputBitDepth = getBitDepthFromDevice (kAudioDevicePropertyScopeOutput);
|
||||
|
||||
bitDepth = jmax (inputBitDepth, outputBitDepth);
|
||||
if (bitDepth <= 0)
|
||||
bitDepth = 32;
|
||||
|
||||
// after getting the new values, lock + apply them
|
||||
const ScopedLock sl (callbackLock);
|
||||
|
||||
@@ -728,6 +752,7 @@ public:
|
||||
//==============================================================================
|
||||
CoreAudioIODevice& owner;
|
||||
int inputLatency, outputLatency;
|
||||
int bitDepth;
|
||||
BigInteger activeInputChans, activeOutputChans;
|
||||
StringArray inChanNames, outChanNames;
|
||||
Array<double> sampleRates;
|
||||
@@ -886,7 +911,7 @@ public:
|
||||
Array<int> getAvailableBufferSizes() override { return internal->bufferSizes; }
|
||||
|
||||
double getCurrentSampleRate() override { return internal->getSampleRate(); }
|
||||
int getCurrentBitDepth() override { return 32; } // no way to find out, so just assume it's high..
|
||||
int getCurrentBitDepth() override { return internal->bitDepth; }
|
||||
int getCurrentBufferSizeSamples() override { return internal->getBufferSize(); }
|
||||
|
||||
int getDefaultBufferSize() override
|
||||
@@ -1387,7 +1412,7 @@ private:
|
||||
d.done = (d.numInputChans == 0);
|
||||
}
|
||||
|
||||
for (int tries = 3;;)
|
||||
for (int tries = 5;;)
|
||||
{
|
||||
bool anyRemaining = false;
|
||||
|
||||
@@ -1434,7 +1459,7 @@ private:
|
||||
d.done = (d.numOutputChans == 0);
|
||||
}
|
||||
|
||||
for (int tries = 3;;)
|
||||
for (int tries = 5;;)
|
||||
{
|
||||
bool anyRemaining = false;
|
||||
|
||||
|
||||
@@ -365,7 +365,7 @@ public:
|
||||
void updateSampleRates()
|
||||
{
|
||||
// find a list of sample rates..
|
||||
const int possibleSampleRates[] = { 44100, 48000, 88200, 96000, 176400, 192000 };
|
||||
const int possibleSampleRates[] = { 44100, 48000, 88200, 96000, 176400, 192000, 352800, 384000 };
|
||||
Array<double> newRates;
|
||||
|
||||
if (asioObject != nullptr)
|
||||
|
||||
@@ -33,8 +33,8 @@ namespace WasapiClasses
|
||||
void logFailure (HRESULT hr)
|
||||
{
|
||||
(void) hr;
|
||||
jassert (hr != 0x800401f0); // If you hit this, it means you're trying to call from
|
||||
// a thread which hasn't been initialised with CoInitialize().
|
||||
jassert (hr != (HRESULT) 0x800401f0); // If you hit this, it means you're trying to call from
|
||||
// a thread which hasn't been initialised with CoInitialize().
|
||||
|
||||
#if JUCE_WASAPI_LOGGING
|
||||
if (FAILED (hr))
|
||||
|
||||
@@ -182,6 +182,10 @@ void AudioTransportSource::setNextReadPosition (int64 newPosition)
|
||||
newPosition = (int64) (newPosition * sourceSampleRate / sampleRate);
|
||||
|
||||
positionableSource->setNextReadPosition (newPosition);
|
||||
|
||||
if (resamplerSource != nullptr)
|
||||
resamplerSource->flushBuffers();
|
||||
|
||||
inputStreamEOF = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ const char* const AiffAudioFormat::appleKey = "apple key";
|
||||
//==============================================================================
|
||||
namespace AiffFileHelpers
|
||||
{
|
||||
inline int chunkName (const char* const name) { return (int) ByteOrder::littleEndianInt (name); }
|
||||
inline int chunkName (const char* name) noexcept { return (int) ByteOrder::littleEndianInt (name); }
|
||||
|
||||
#if JUCE_MSVC
|
||||
#pragma pack (push, 1)
|
||||
@@ -888,13 +888,13 @@ AiffAudioFormat::~AiffAudioFormat()
|
||||
Array<int> AiffAudioFormat::getPossibleSampleRates()
|
||||
{
|
||||
const int rates[] = { 22050, 32000, 44100, 48000, 88200, 96000, 176400, 192000, 0 };
|
||||
return Array <int> (rates);
|
||||
return Array<int> (rates);
|
||||
}
|
||||
|
||||
Array<int> AiffAudioFormat::getPossibleBitDepths()
|
||||
{
|
||||
const int depths[] = { 8, 16, 24, 0 };
|
||||
return Array <int> (depths);
|
||||
return Array<int> (depths);
|
||||
}
|
||||
|
||||
bool AiffAudioFormat::canDoStereo() { return true; }
|
||||
|
||||
@@ -165,13 +165,13 @@ bool LAMEEncoderAudioFormat::canHandleFile (const File&)
|
||||
Array<int> LAMEEncoderAudioFormat::getPossibleSampleRates()
|
||||
{
|
||||
const int rates[] = { 32000, 44100, 48000, 0 };
|
||||
return Array <int> (rates);
|
||||
return Array<int> (rates);
|
||||
}
|
||||
|
||||
Array<int> LAMEEncoderAudioFormat::getPossibleBitDepths()
|
||||
{
|
||||
const int depths[] = { 16, 0 };
|
||||
return Array <int> (depths);
|
||||
return Array<int> (depths);
|
||||
}
|
||||
|
||||
bool LAMEEncoderAudioFormat::canDoStereo() { return true; }
|
||||
|
||||
@@ -65,6 +65,7 @@ const char* const WavAudioFormat::acidNumerator = "acid numerator";
|
||||
const char* const WavAudioFormat::acidTempo = "acid tempo";
|
||||
|
||||
const char* const WavAudioFormat::ISRC = "ISRC";
|
||||
const char* const WavAudioFormat::tracktionLoopInfo = "tracktion loop info";
|
||||
|
||||
//==============================================================================
|
||||
namespace WavFileHelpers
|
||||
@@ -471,6 +472,46 @@ namespace WavFileHelpers
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
namespace ListInfoChunk
|
||||
{
|
||||
static bool writeValue (const StringPairArray& values, MemoryOutputStream& out, const char* paramName)
|
||||
{
|
||||
const String value (values.getValue (paramName, String()));
|
||||
|
||||
if (value.isEmpty())
|
||||
return false;
|
||||
|
||||
const int valueLength = (int) value.getNumBytesAsUTF8() + 1;
|
||||
const int chunkLength = valueLength + (valueLength & 1);
|
||||
|
||||
out.writeInt (chunkName (paramName));
|
||||
out.writeInt (chunkLength);
|
||||
out.write (value.toUTF8(), (size_t) valueLength);
|
||||
|
||||
if ((out.getDataSize() & 1) != 0)
|
||||
out.writeByte (0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static MemoryBlock createFrom (const StringPairArray& values)
|
||||
{
|
||||
static const char* params[] = { "INAM", "IART", "IPRD", "IPRT", "ISFT",
|
||||
"ISRC", "IGNR", "ICMT", "ICOP", "ICRD" };
|
||||
|
||||
MemoryOutputStream out;
|
||||
out.writeInt (chunkName ("INFO"));
|
||||
bool anyParamsDefined = false;
|
||||
|
||||
for (int i = 0; i < numElementsInArray (params); ++i)
|
||||
if (writeValue (values, out, params[i]))
|
||||
anyParamsDefined = true;
|
||||
|
||||
return anyParamsDefined ? out.getMemoryBlock() : MemoryBlock();
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
struct AcidChunk
|
||||
{
|
||||
@@ -481,6 +522,38 @@ namespace WavFileHelpers
|
||||
input.read (this, (int) jmin (sizeof (*this), length));
|
||||
}
|
||||
|
||||
AcidChunk (const StringPairArray& values)
|
||||
{
|
||||
zerostruct (*this);
|
||||
|
||||
flags = getFlagIfPresent (values, WavAudioFormat::acidOneShot, 0x01)
|
||||
| getFlagIfPresent (values, WavAudioFormat::acidRootSet, 0x02)
|
||||
| getFlagIfPresent (values, WavAudioFormat::acidStretch, 0x04)
|
||||
| getFlagIfPresent (values, WavAudioFormat::acidDiskBased, 0x08)
|
||||
| getFlagIfPresent (values, WavAudioFormat::acidizerFlag, 0x10);
|
||||
|
||||
if (values[WavAudioFormat::acidRootSet].getIntValue() != 0)
|
||||
rootNote = ByteOrder::swapIfBigEndian ((uint16) values[WavAudioFormat::acidRootNote].getIntValue());
|
||||
|
||||
numBeats = ByteOrder::swapIfBigEndian ((uint32) values[WavAudioFormat::acidBeats].getIntValue());
|
||||
meterDenominator = ByteOrder::swapIfBigEndian ((uint16) values[WavAudioFormat::acidDenominator].getIntValue());
|
||||
meterNumerator = ByteOrder::swapIfBigEndian ((uint16) values[WavAudioFormat::acidNumerator].getIntValue());
|
||||
|
||||
if (values.containsKey (WavAudioFormat::acidTempo))
|
||||
tempo = swapFloatByteOrder (values[WavAudioFormat::acidTempo].getFloatValue());
|
||||
}
|
||||
|
||||
static MemoryBlock createFrom (const StringPairArray& values)
|
||||
{
|
||||
return AcidChunk (values).toMemoryBlock();
|
||||
}
|
||||
|
||||
MemoryBlock toMemoryBlock() const
|
||||
{
|
||||
return (flags != 0 || rootNote != 0 || numBeats != 0 || meterDenominator != 0 || meterNumerator != 0)
|
||||
? MemoryBlock (this, sizeof (*this)) : MemoryBlock();
|
||||
}
|
||||
|
||||
void addToMetadata (StringPairArray& values) const
|
||||
{
|
||||
setBoolFlag (values, WavAudioFormat::acidOneShot, 0x01);
|
||||
@@ -490,30 +563,65 @@ namespace WavFileHelpers
|
||||
setBoolFlag (values, WavAudioFormat::acidizerFlag, 0x10);
|
||||
|
||||
if (flags & 0x02) // root note set
|
||||
values.set (WavAudioFormat::acidRootNote, String (rootNote));
|
||||
values.set (WavAudioFormat::acidRootNote, String (ByteOrder::swapIfBigEndian (rootNote)));
|
||||
|
||||
values.set (WavAudioFormat::acidBeats, String (numBeats));
|
||||
values.set (WavAudioFormat::acidDenominator, String (meterDenominator));
|
||||
values.set (WavAudioFormat::acidNumerator, String (meterNumerator));
|
||||
values.set (WavAudioFormat::acidTempo, String (tempo));
|
||||
values.set (WavAudioFormat::acidBeats, String (ByteOrder::swapIfBigEndian (numBeats)));
|
||||
values.set (WavAudioFormat::acidDenominator, String (ByteOrder::swapIfBigEndian (meterDenominator)));
|
||||
values.set (WavAudioFormat::acidNumerator, String (ByteOrder::swapIfBigEndian (meterNumerator)));
|
||||
values.set (WavAudioFormat::acidTempo, String (swapFloatByteOrder (tempo)));
|
||||
}
|
||||
|
||||
void setBoolFlag (StringPairArray& values, const char* name, int32 mask) const
|
||||
void setBoolFlag (StringPairArray& values, const char* name, uint32 mask) const
|
||||
{
|
||||
values.set (name, (flags & mask) ? "1" : "0");
|
||||
values.set (name, (flags & ByteOrder::swapIfBigEndian (mask)) ? "1" : "0");
|
||||
}
|
||||
|
||||
int32 flags;
|
||||
int16 rootNote;
|
||||
int16 reserved1;
|
||||
static uint32 getFlagIfPresent (const StringPairArray& values, const char* name, uint32 flag)
|
||||
{
|
||||
return values[name].getIntValue() != 0 ? ByteOrder::swapIfBigEndian (flag) : 0;
|
||||
}
|
||||
|
||||
static float swapFloatByteOrder (const float x) noexcept
|
||||
{
|
||||
#ifdef JUCE_BIG_ENDIAN
|
||||
union { uint32 asInt; float asFloat; } n;
|
||||
n.asFloat = x;
|
||||
n.asInt = ByteOrder::swap (n.asInt);
|
||||
return n.asFloat;
|
||||
#else
|
||||
return x;
|
||||
#endif
|
||||
}
|
||||
|
||||
uint32 flags;
|
||||
uint16 rootNote;
|
||||
uint16 reserved1;
|
||||
float reserved2;
|
||||
int32 numBeats;
|
||||
int16 meterDenominator;
|
||||
int16 meterNumerator;
|
||||
uint32 numBeats;
|
||||
uint16 meterDenominator;
|
||||
uint16 meterNumerator;
|
||||
float tempo;
|
||||
|
||||
} JUCE_PACKED;
|
||||
|
||||
//==============================================================================
|
||||
struct TracktionChunk
|
||||
{
|
||||
static MemoryBlock createFrom (const StringPairArray& values)
|
||||
{
|
||||
const String s = values[WavAudioFormat::tracktionLoopInfo];
|
||||
MemoryBlock data;
|
||||
|
||||
if (s.isNotEmpty())
|
||||
{
|
||||
MemoryOutputStream os (data, false);
|
||||
os.writeString (s);
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
namespace AXMLChunk
|
||||
{
|
||||
@@ -816,6 +924,12 @@ public:
|
||||
{
|
||||
AcidChunk (*input, length).addToMetadata (metadataValues);
|
||||
}
|
||||
else if (chunkType == chunkName ("Trkn"))
|
||||
{
|
||||
MemoryBlock tracktion;
|
||||
input->readIntoMemoryBlock (tracktion, (ssize_t) length);
|
||||
metadataValues.set (WavAudioFormat::tracktionLoopInfo, tracktion.toString());
|
||||
}
|
||||
else if (chunkEnd <= input->getPosition())
|
||||
{
|
||||
break;
|
||||
@@ -913,12 +1027,15 @@ public:
|
||||
// key should be removed (or set to "WAV") once this has been done
|
||||
jassert (metadataValues.getValue ("MetaDataSource", "None") != "AIFF");
|
||||
|
||||
bwavChunk = BWAVChunk::createFrom (metadataValues);
|
||||
axmlChunk = AXMLChunk::createFrom (metadataValues);
|
||||
smplChunk = SMPLChunk::createFrom (metadataValues);
|
||||
instChunk = InstChunk::createFrom (metadataValues);
|
||||
cueChunk = CueChunk ::createFrom (metadataValues);
|
||||
listChunk = ListChunk::createFrom (metadataValues);
|
||||
bwavChunk = BWAVChunk::createFrom (metadataValues);
|
||||
axmlChunk = AXMLChunk::createFrom (metadataValues);
|
||||
smplChunk = SMPLChunk::createFrom (metadataValues);
|
||||
instChunk = InstChunk::createFrom (metadataValues);
|
||||
cueChunk = CueChunk ::createFrom (metadataValues);
|
||||
listChunk = ListChunk::createFrom (metadataValues);
|
||||
listInfoChunk = ListInfoChunk::createFrom (metadataValues);
|
||||
acidChunk = AcidChunk::createFrom (metadataValues);
|
||||
trckChunk = TracktionChunk::createFrom (metadataValues);
|
||||
}
|
||||
|
||||
headerPosition = out->getPosition();
|
||||
@@ -927,12 +1044,6 @@ public:
|
||||
|
||||
~WavAudioFormatWriter()
|
||||
{
|
||||
if ((bytesWritten & 1) != 0) // pad to an even length
|
||||
{
|
||||
++bytesWritten;
|
||||
output->writeByte (0);
|
||||
}
|
||||
|
||||
writeHeader();
|
||||
}
|
||||
|
||||
@@ -972,8 +1083,22 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
bool flush() override
|
||||
{
|
||||
const int64 lastWritePos = output->getPosition();
|
||||
writeHeader();
|
||||
|
||||
if (output->setPosition (lastWritePos))
|
||||
return true;
|
||||
|
||||
// if this fails, you've given it an output stream that can't seek! It needs
|
||||
// to be able to seek back to write the header
|
||||
jassertfalse;
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
MemoryBlock tempBlock, bwavChunk, axmlChunk, smplChunk, instChunk, cueChunk, listChunk;
|
||||
MemoryBlock tempBlock, bwavChunk, axmlChunk, smplChunk, instChunk, cueChunk, listChunk, listInfoChunk, acidChunk, trckChunk;
|
||||
uint64 lengthInSamples, bytesWritten;
|
||||
int64 headerPosition;
|
||||
bool writeFailed;
|
||||
@@ -998,13 +1123,18 @@ private:
|
||||
|
||||
void writeHeader()
|
||||
{
|
||||
using namespace WavFileHelpers;
|
||||
const bool seekedOk = output->setPosition (headerPosition);
|
||||
(void) seekedOk;
|
||||
if ((bytesWritten & 1) != 0) // pad to an even length
|
||||
output->writeByte (0);
|
||||
|
||||
// if this fails, you've given it an output stream that can't seek! It needs
|
||||
// to be able to seek back to write the header
|
||||
jassert (seekedOk);
|
||||
using namespace WavFileHelpers;
|
||||
|
||||
if (headerPosition != output->getPosition() && ! output->setPosition (headerPosition))
|
||||
{
|
||||
// if this fails, you've given it an output stream that can't seek! It needs to be
|
||||
// able to seek back to go back and write the header after the data has been written.
|
||||
jassertfalse;
|
||||
return;
|
||||
}
|
||||
|
||||
const size_t bytesPerFrame = numChannels * bitsPerSample / 8;
|
||||
uint64 audioDataSize = bytesPerFrame * lengthInSamples;
|
||||
@@ -1020,6 +1150,9 @@ private:
|
||||
+ chunkSize (instChunk)
|
||||
+ chunkSize (cueChunk)
|
||||
+ chunkSize (listChunk)
|
||||
+ chunkSize (listInfoChunk)
|
||||
+ chunkSize (acidChunk)
|
||||
+ chunkSize (trckChunk)
|
||||
+ (8 + 28)); // (ds64 chunk)
|
||||
|
||||
riffChunkSize += (riffChunkSize & 1);
|
||||
@@ -1093,12 +1226,15 @@ private:
|
||||
output->write (subFormat.data4, sizeof (subFormat.data4));
|
||||
}
|
||||
|
||||
writeChunk (bwavChunk, chunkName ("bext"));
|
||||
writeChunk (axmlChunk, chunkName ("axml"));
|
||||
writeChunk (smplChunk, chunkName ("smpl"));
|
||||
writeChunk (instChunk, chunkName ("inst"), 7);
|
||||
writeChunk (cueChunk, chunkName ("cue "));
|
||||
writeChunk (listChunk, chunkName ("LIST"));
|
||||
writeChunk (bwavChunk, chunkName ("bext"));
|
||||
writeChunk (axmlChunk, chunkName ("axml"));
|
||||
writeChunk (smplChunk, chunkName ("smpl"));
|
||||
writeChunk (instChunk, chunkName ("inst"), 7);
|
||||
writeChunk (cueChunk, chunkName ("cue "));
|
||||
writeChunk (listChunk, chunkName ("LIST"));
|
||||
writeChunk (listInfoChunk, chunkName ("LIST"));
|
||||
writeChunk (acidChunk, chunkName ("acid"));
|
||||
writeChunk (trckChunk, chunkName ("Trkn"));
|
||||
|
||||
writeChunkHeader (chunkName ("data"), isRF64 ? -1 : (int) (lengthInSamples * bytesPerFrame));
|
||||
|
||||
|
||||
@@ -135,6 +135,9 @@ public:
|
||||
/** Metadata property name used when reading an ISRC code from an AXML chunk. */
|
||||
static const char* const ISRC;
|
||||
|
||||
/** Metadata property name used when reading a WAV file with a Tracktion chunk. */
|
||||
static const char* const tracktionLoopInfo;
|
||||
|
||||
//==============================================================================
|
||||
Array<int> getPossibleSampleRates() override;
|
||||
Array<int> getPossibleBitDepths() override;
|
||||
|
||||
@@ -162,7 +162,7 @@ void AudioFormatReader::read (AudioSampleBuffer* buffer,
|
||||
}
|
||||
else
|
||||
{
|
||||
HeapBlock<int*> chans (numTargetChannels);
|
||||
HeapBlock<int*> chans ((size_t) numTargetChannels);
|
||||
readChannels (*this, chans, buffer, startSample, numSamples, readerStartSample, numTargetChannels);
|
||||
}
|
||||
|
||||
@@ -173,35 +173,54 @@ void AudioFormatReader::read (AudioSampleBuffer* buffer,
|
||||
}
|
||||
}
|
||||
|
||||
template <typename SampleType>
|
||||
static Range<SampleType> getChannelMinAndMax (SampleType* channel, int numSamples) noexcept
|
||||
void AudioFormatReader::readMaxLevels (int64 startSampleInFile, int64 numSamples,
|
||||
Range<float>* const results, const int channelsToRead)
|
||||
{
|
||||
return Range<SampleType>::findMinAndMax (channel, numSamples);
|
||||
}
|
||||
jassert (channelsToRead > 0 && channelsToRead <= (int) numChannels);
|
||||
|
||||
static Range<float> getChannelMinAndMax (float* channel, int numSamples) noexcept
|
||||
{
|
||||
return FloatVectorOperations::findMinAndMax (channel, numSamples);
|
||||
}
|
||||
|
||||
template <typename SampleType>
|
||||
static void getStereoMinAndMax (SampleType* const* channels, const int numChannels, const int numSamples,
|
||||
SampleType& lmin, SampleType& lmax, SampleType& rmin, SampleType& rmax)
|
||||
{
|
||||
Range<SampleType> range (getChannelMinAndMax (channels[0], numSamples));
|
||||
lmax = jmax (lmax, range.getEnd());
|
||||
lmin = jmin (lmin, range.getStart());
|
||||
|
||||
if (numChannels > 1)
|
||||
if (numSamples <= 0)
|
||||
{
|
||||
range = getChannelMinAndMax (channels[1], numSamples);
|
||||
rmax = jmax (rmax, range.getEnd());
|
||||
rmin = jmin (rmin, range.getStart());
|
||||
for (int i = 0; i < channelsToRead; ++i)
|
||||
results[i] = Range<float>();
|
||||
|
||||
return;
|
||||
}
|
||||
else
|
||||
|
||||
const int bufferSize = (int) jmin (numSamples, (int64) 4096);
|
||||
AudioSampleBuffer tempSampleBuffer ((int) channelsToRead, bufferSize);
|
||||
|
||||
float* const* const floatBuffer = tempSampleBuffer.getArrayOfWritePointers();
|
||||
int* const* intBuffer = reinterpret_cast<int* const*> (floatBuffer);
|
||||
bool isFirstBlock = true;
|
||||
|
||||
while (numSamples > 0)
|
||||
{
|
||||
rmax = lmax;
|
||||
rmin = lmin;
|
||||
const int numToDo = (int) jmin (numSamples, (int64) bufferSize);
|
||||
if (! read (intBuffer, channelsToRead, startSampleInFile, numToDo, false))
|
||||
break;
|
||||
|
||||
for (int i = 0; i < channelsToRead; ++i)
|
||||
{
|
||||
Range<float> r;
|
||||
|
||||
if (usesFloatingPointData)
|
||||
{
|
||||
r = FloatVectorOperations::findMinAndMax (floatBuffer[i], numToDo);
|
||||
}
|
||||
else
|
||||
{
|
||||
Range<int> intRange (Range<int>::findMinAndMax (intBuffer[i], numToDo));
|
||||
|
||||
r = Range<float> (intRange.getStart() / (float) std::numeric_limits<int>::max(),
|
||||
intRange.getEnd() / (float) std::numeric_limits<int>::max());
|
||||
}
|
||||
|
||||
results[i] = isFirstBlock ? r : results[i].getUnionWith (r);
|
||||
}
|
||||
|
||||
isFirstBlock = false;
|
||||
numSamples -= numToDo;
|
||||
startSampleInFile += numToDo;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -209,66 +228,20 @@ void AudioFormatReader::readMaxLevels (int64 startSampleInFile, int64 numSamples
|
||||
float& lowestLeft, float& highestLeft,
|
||||
float& lowestRight, float& highestRight)
|
||||
{
|
||||
if (numSamples <= 0)
|
||||
Range<float> levels[2];
|
||||
readMaxLevels (startSampleInFile, numSamples, levels, jmin (2, (int) numChannels));
|
||||
lowestLeft = levels[0].getStart();
|
||||
highestLeft = levels[0].getEnd();
|
||||
|
||||
if (numChannels > 1)
|
||||
{
|
||||
lowestLeft = 0;
|
||||
lowestRight = 0;
|
||||
highestLeft = 0;
|
||||
highestRight = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
const int bufferSize = (int) jmin (numSamples, (int64) 4096);
|
||||
AudioSampleBuffer tempSampleBuffer ((int) numChannels, bufferSize);
|
||||
|
||||
float* const* const floatBuffer = tempSampleBuffer.getArrayOfWritePointers();
|
||||
int* const* intBuffer = reinterpret_cast<int* const*> (floatBuffer);
|
||||
|
||||
if (usesFloatingPointData)
|
||||
{
|
||||
float lmin = 1.0e6f;
|
||||
float lmax = -lmin;
|
||||
float rmin = lmin;
|
||||
float rmax = lmax;
|
||||
|
||||
while (numSamples > 0)
|
||||
{
|
||||
const int numToDo = (int) jmin (numSamples, (int64) bufferSize);
|
||||
if (! read (intBuffer, 2, startSampleInFile, numToDo, false))
|
||||
break;
|
||||
|
||||
numSamples -= numToDo;
|
||||
startSampleInFile += numToDo;
|
||||
getStereoMinAndMax (floatBuffer, (int) numChannels, numToDo, lmin, lmax, rmin, rmax);
|
||||
}
|
||||
|
||||
lowestLeft = lmin;
|
||||
highestLeft = lmax;
|
||||
lowestRight = rmin;
|
||||
highestRight = rmax;
|
||||
lowestRight = levels[1].getStart();
|
||||
highestRight = levels[1].getEnd();
|
||||
}
|
||||
else
|
||||
{
|
||||
int lmax = std::numeric_limits<int>::min();
|
||||
int lmin = std::numeric_limits<int>::max();
|
||||
int rmax = std::numeric_limits<int>::min();
|
||||
int rmin = std::numeric_limits<int>::max();
|
||||
|
||||
while (numSamples > 0)
|
||||
{
|
||||
const int numToDo = (int) jmin (numSamples, (int64) bufferSize);
|
||||
if (! read (intBuffer, 2, startSampleInFile, numToDo, false))
|
||||
break;
|
||||
|
||||
numSamples -= numToDo;
|
||||
startSampleInFile += numToDo;
|
||||
getStereoMinAndMax (intBuffer, (int) numChannels, numToDo, lmin, lmax, rmin, rmax);
|
||||
}
|
||||
|
||||
lowestLeft = lmin / (float) std::numeric_limits<int>::max();
|
||||
highestLeft = lmax / (float) std::numeric_limits<int>::max();
|
||||
lowestRight = rmin / (float) std::numeric_limits<int>::max();
|
||||
highestRight = rmax / (float) std::numeric_limits<int>::max();
|
||||
lowestRight = lowestLeft;
|
||||
highestRight = highestLeft;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -121,6 +121,25 @@ public:
|
||||
bool useReaderLeftChan,
|
||||
bool useReaderRightChan);
|
||||
|
||||
/** Finds the highest and lowest sample levels from a section of the audio stream.
|
||||
|
||||
This will read a block of samples from the stream, and measure the
|
||||
highest and lowest sample levels from the channels in that section, returning
|
||||
these as normalised floating-point levels.
|
||||
|
||||
@param startSample the offset into the audio stream to start reading from. It's
|
||||
ok for this to be beyond the start or end of the stream.
|
||||
@param numSamples how many samples to read
|
||||
@param results this array will be filled with Range values for each channel.
|
||||
The array must contain numChannels elements.
|
||||
@param numChannelsToRead the number of channels of data to scan. This must be
|
||||
more than zero, but not more than the total number of channels
|
||||
that the reader contains
|
||||
@see read
|
||||
*/
|
||||
virtual void readMaxLevels (int64 startSample, int64 numSamples,
|
||||
Range<float>* results, int numChannelsToRead);
|
||||
|
||||
/** Finds the highest and lowest sample levels from a section of the audio stream.
|
||||
|
||||
This will read a block of samples from the stream, and measure the
|
||||
@@ -138,12 +157,9 @@ public:
|
||||
channel (if there is one)
|
||||
@see read
|
||||
*/
|
||||
virtual void readMaxLevels (int64 startSample,
|
||||
int64 numSamples,
|
||||
float& lowestLeft,
|
||||
float& highestLeft,
|
||||
float& lowestRight,
|
||||
float& highestRight);
|
||||
virtual void readMaxLevels (int64 startSample, int64 numSamples,
|
||||
float& lowestLeft, float& highestLeft,
|
||||
float& lowestRight, float& highestRight);
|
||||
|
||||
/** Scans the source looking for a sample whose magnitude is in a specified range.
|
||||
|
||||
|
||||
@@ -183,6 +183,11 @@ bool AudioFormatWriter::writeFromAudioSampleBuffer (const AudioSampleBuffer& sou
|
||||
return writeFromFloatArrays (chans, numSourceChannels, numSamples);
|
||||
}
|
||||
|
||||
bool AudioFormatWriter::flush()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
class AudioFormatWriter::ThreadedWriter::Buffer : private TimeSliceClient
|
||||
{
|
||||
@@ -194,6 +199,8 @@ public:
|
||||
writer (w),
|
||||
receiver (nullptr),
|
||||
samplesWritten (0),
|
||||
samplesPerFlush (0),
|
||||
flushSampleCounter (0),
|
||||
isRunning (true)
|
||||
{
|
||||
timeSliceThread.addTimeSliceClient (this);
|
||||
@@ -266,6 +273,18 @@ public:
|
||||
}
|
||||
|
||||
fifo.finishedRead (size1 + size2);
|
||||
|
||||
if (samplesPerFlush > 0)
|
||||
{
|
||||
flushSampleCounter -= size1 + size2;
|
||||
|
||||
if (flushSampleCounter <= 0)
|
||||
{
|
||||
flushSampleCounter = samplesPerFlush;
|
||||
writer->flush();
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -279,6 +298,11 @@ public:
|
||||
samplesWritten = 0;
|
||||
}
|
||||
|
||||
void setFlushInterval (int numSamples) noexcept
|
||||
{
|
||||
samplesPerFlush = numSamples;
|
||||
}
|
||||
|
||||
private:
|
||||
AbstractFifo fifo;
|
||||
AudioSampleBuffer buffer;
|
||||
@@ -287,6 +311,7 @@ private:
|
||||
CriticalSection thumbnailLock;
|
||||
IncomingDataReceiver* receiver;
|
||||
int64 samplesWritten;
|
||||
int samplesPerFlush, flushSampleCounter;
|
||||
volatile bool isRunning;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE (Buffer)
|
||||
@@ -310,3 +335,8 @@ void AudioFormatWriter::ThreadedWriter::setDataReceiver (AudioFormatWriter::Thre
|
||||
{
|
||||
buffer->setDataReceiver (receiver);
|
||||
}
|
||||
|
||||
void AudioFormatWriter::ThreadedWriter::setFlushInterval (int numSamplesPerFlush) noexcept
|
||||
{
|
||||
buffer->setFlushInterval (numSamplesPerFlush);
|
||||
}
|
||||
|
||||
@@ -91,8 +91,18 @@ public:
|
||||
to pass it into the method.
|
||||
@param numSamples the number of samples to write
|
||||
*/
|
||||
virtual bool write (const int** samplesToWrite,
|
||||
int numSamples) = 0;
|
||||
virtual bool write (const int** samplesToWrite, int numSamples) = 0;
|
||||
|
||||
/** Some formats may support a flush operation that makes sure the file is in a
|
||||
valid state before carrying on.
|
||||
If supported, this means that by calling flush periodically when writing data
|
||||
to a large file, then it should still be left in a readable state if your program
|
||||
crashes.
|
||||
It goes without saying that this method must be called from the same thread that's
|
||||
calling write()!
|
||||
If the format supports flushing and the operation succeeds, this returns true.
|
||||
*/
|
||||
virtual bool flush();
|
||||
|
||||
//==============================================================================
|
||||
/** Reads a section of samples from an AudioFormatReader, and writes these to
|
||||
@@ -197,7 +207,12 @@ public:
|
||||
|
||||
The object passed-in must not be deleted while this writer is still using it.
|
||||
*/
|
||||
void setDataReceiver (IncomingDataReceiver* receiver);
|
||||
void setDataReceiver (IncomingDataReceiver*);
|
||||
|
||||
/** Sets how many samples should be written before calling the AudioFormatWriter::flush method.
|
||||
Set this to 0 to disable flushing (this is the default).
|
||||
*/
|
||||
void setFlushInterval (int numSamplesPerFlush) noexcept;
|
||||
|
||||
private:
|
||||
class Buffer;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"id": "juce_audio_formats",
|
||||
"name": "JUCE audio file format codecs",
|
||||
"version": "3.0.5",
|
||||
"version": "3.0.8",
|
||||
"description": "Classes for reading and writing various audio file formats.",
|
||||
"website": "http://www.juce.com/juce",
|
||||
"license": "GPL/Commercial",
|
||||
|
||||
@@ -59,12 +59,12 @@ SamplerSound::~SamplerSound()
|
||||
{
|
||||
}
|
||||
|
||||
bool SamplerSound::appliesToNote (const int midiNoteNumber)
|
||||
bool SamplerSound::appliesToNote (int midiNoteNumber)
|
||||
{
|
||||
return midiNotes [midiNoteNumber];
|
||||
}
|
||||
|
||||
bool SamplerSound::appliesToChannel (const int /*midiChannel*/)
|
||||
bool SamplerSound::appliesToChannel (int /*midiChannel*/)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@@ -127,7 +127,7 @@ void SamplerVoice::startNote (const int midiNoteNumber,
|
||||
}
|
||||
}
|
||||
|
||||
void SamplerVoice::stopNote (const bool allowTailOff)
|
||||
void SamplerVoice::stopNote (float /*velocity*/, bool allowTailOff)
|
||||
{
|
||||
if (allowTailOff)
|
||||
{
|
||||
@@ -197,7 +197,7 @@ void SamplerVoice::renderNextBlock (AudioSampleBuffer& outputBuffer, int startSa
|
||||
|
||||
if (attackReleaseLevel <= 0.0f)
|
||||
{
|
||||
stopNote (false);
|
||||
stopNote (0.0f, false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -216,7 +216,7 @@ void SamplerVoice::renderNextBlock (AudioSampleBuffer& outputBuffer, int startSa
|
||||
|
||||
if (sourceSamplePosition > playingSound->length)
|
||||
{
|
||||
stopNote (false);
|
||||
stopNote (0.0f, false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,8 +82,8 @@ public:
|
||||
|
||||
|
||||
//==============================================================================
|
||||
bool appliesToNote (const int midiNoteNumber) override;
|
||||
bool appliesToChannel (const int midiChannel) override;
|
||||
bool appliesToNote (int midiNoteNumber) override;
|
||||
bool appliesToChannel (int midiChannel) override;
|
||||
|
||||
|
||||
private:
|
||||
@@ -124,7 +124,7 @@ public:
|
||||
bool canPlaySound (SynthesiserSound*) override;
|
||||
|
||||
void startNote (int midiNoteNumber, float velocity, SynthesiserSound*, int pitchWheel) override;
|
||||
void stopNote (bool allowTailOff) override;
|
||||
void stopNote (float velocity, bool allowTailOff) override;
|
||||
|
||||
void pitchWheelMoved (int newValue);
|
||||
void controllerMoved (int controllerNumber, int newValue) override;
|
||||
|
||||
@@ -54,7 +54,7 @@ public:
|
||||
(e.g. VST shells) can use a single DLL to create a set of different plugin
|
||||
subtypes, so in that case, each subtype is returned as a separate object.
|
||||
*/
|
||||
virtual void findAllTypesForFile (OwnedArray <PluginDescription>& results,
|
||||
virtual void findAllTypesForFile (OwnedArray<PluginDescription>& results,
|
||||
const String& fileOrIdentifier) = 0;
|
||||
|
||||
/** Tries to recreate a type from a previously generated PluginDescription.
|
||||
|
||||
+1
-1
@@ -89,7 +89,7 @@ public:
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
OwnedArray <AudioPluginFormat> formats;
|
||||
OwnedArray<AudioPluginFormat> formats;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioPluginFormatManager)
|
||||
};
|
||||
|
||||
+1
-1
@@ -37,7 +37,7 @@ public:
|
||||
|
||||
//==============================================================================
|
||||
String getName() const override { return "AudioUnit"; }
|
||||
void findAllTypesForFile (OwnedArray <PluginDescription>&, const String& fileOrIdentifier) override;
|
||||
void findAllTypesForFile (OwnedArray<PluginDescription>&, const String& fileOrIdentifier) override;
|
||||
AudioPluginInstance* createInstanceFromDescription (const PluginDescription& desc, double, int) override;
|
||||
bool fileMightContainThisPluginType (const String& fileOrIdentifier) override;
|
||||
String getNameOfPluginFromIdentifier (const String& fileOrIdentifier) override;
|
||||
|
||||
+34
-19
@@ -62,7 +62,7 @@ namespace AudioUnitFormatHelpers
|
||||
static ThreadLocalValue<int> insideCallback;
|
||||
#endif
|
||||
|
||||
String osTypeToString (OSType type)
|
||||
String osTypeToString (OSType type) noexcept
|
||||
{
|
||||
const juce_wchar s[4] = { (juce_wchar) ((type >> 24) & 0xff),
|
||||
(juce_wchar) ((type >> 16) & 0xff),
|
||||
@@ -88,9 +88,6 @@ namespace AudioUnitFormatHelpers
|
||||
|
||||
String createPluginIdentifier (const AudioComponentDescription& desc)
|
||||
{
|
||||
jassert (osTypeToString ('abcd') == "abcd"); // agh, must have got the endianness wrong..
|
||||
jassert (stringToOSType ("abcd") == (OSType) 'abcd'); // ditto
|
||||
|
||||
String s (auIdentifierPrefix);
|
||||
|
||||
if (desc.componentType == kAudioUnitType_MusicDevice)
|
||||
@@ -138,7 +135,7 @@ namespace AudioUnitFormatHelpers
|
||||
fileOrIdentifier.lastIndexOfChar ('/')) + 1));
|
||||
|
||||
StringArray tokens;
|
||||
tokens.addTokens (s, ",", String());
|
||||
tokens.addTokens (s, ",", StringRef());
|
||||
tokens.removeEmptyStrings();
|
||||
|
||||
if (tokens.size() == 3)
|
||||
@@ -215,9 +212,11 @@ namespace AudioUnitFormatHelpers
|
||||
const short resFileId = CFBundleOpenBundleResourceMap (bundleRef);
|
||||
UseResFile (resFileId);
|
||||
|
||||
for (ResourceIndex i = 1; i <= Count1Resources ('thng'); ++i)
|
||||
const OSType thngType = stringToOSType ("thng");
|
||||
|
||||
for (ResourceIndex i = 1; i <= Count1Resources (thngType); ++i)
|
||||
{
|
||||
if (Handle h = Get1IndResource ('thng', i))
|
||||
if (Handle h = Get1IndResource (thngType, i))
|
||||
{
|
||||
HLock (h);
|
||||
const uint32* const types = (const uint32*) *h;
|
||||
@@ -346,11 +345,21 @@ public:
|
||||
refreshParameterList();
|
||||
updateNumChannels();
|
||||
producesMidiMessages = canProduceMidiOutput();
|
||||
setPluginCallbacks();
|
||||
setPlayConfigDetails (numInputBusChannels * numInputBusses,
|
||||
numOutputBusChannels * numOutputBusses,
|
||||
rate, blockSize);
|
||||
setLatencySamples (0);
|
||||
|
||||
if (parameters.size() == 0)
|
||||
{
|
||||
// some plugins crash if initialiseAudioUnit() is called too soon (sigh..), so we'll
|
||||
// only call it here if it seems like they it's one of the awkward plugins that can
|
||||
// only create their parameters after it has been initialised.
|
||||
initialiseAudioUnit();
|
||||
refreshParameterList();
|
||||
}
|
||||
|
||||
setPluginCallbacks();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
@@ -915,7 +924,7 @@ private:
|
||||
bool automatable;
|
||||
};
|
||||
|
||||
OwnedArray <ParamInfo> parameters;
|
||||
OwnedArray<ParamInfo> parameters;
|
||||
|
||||
MidiDataConcatenator midiConcatenator;
|
||||
CriticalSection midiInLock;
|
||||
@@ -972,16 +981,11 @@ private:
|
||||
|
||||
for (int i = 0; i < parameters.size(); ++i)
|
||||
{
|
||||
const ParamInfo& p = *parameters.getUnchecked(i);
|
||||
|
||||
AudioUnitParameter paramToAdd;
|
||||
paramToAdd.mAudioUnit = audioUnit;
|
||||
paramToAdd.mParameterID = p.paramID;
|
||||
paramToAdd.mScope = kAudioUnitScope_Global;
|
||||
paramToAdd.mElement = 0;
|
||||
|
||||
AudioUnitEvent event;
|
||||
event.mArgument.mParameter = paramToAdd;
|
||||
event.mArgument.mParameter.mAudioUnit = audioUnit;
|
||||
event.mArgument.mParameter.mParameterID = parameters.getUnchecked(i)->paramID;
|
||||
event.mArgument.mParameter.mScope = kAudioUnitScope_Global;
|
||||
event.mArgument.mParameter.mElement = 0;
|
||||
|
||||
event.mEventType = kAudioUnitEvent_ParameterValueChange;
|
||||
AUEventListenerAddEventType (eventListenerRef, nullptr, &event);
|
||||
@@ -992,6 +996,16 @@ private:
|
||||
event.mEventType = kAudioUnitEvent_EndParameterChangeGesture;
|
||||
AUEventListenerAddEventType (eventListenerRef, nullptr, &event);
|
||||
}
|
||||
|
||||
// Add a listener for program changes
|
||||
AudioUnitEvent event;
|
||||
event.mArgument.mProperty.mAudioUnit = audioUnit;
|
||||
event.mArgument.mProperty.mPropertyID = kAudioUnitProperty_PresentPreset;
|
||||
event.mArgument.mProperty.mScope = kAudioUnitScope_Global;
|
||||
event.mArgument.mProperty.mElement = 0;
|
||||
|
||||
event.mEventType = kAudioUnitEvent_PropertyChange;
|
||||
AUEventListenerAddEventType (eventListenerRef, nullptr, &event);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1022,6 +1036,7 @@ private:
|
||||
break;
|
||||
|
||||
default:
|
||||
sendAllParametersChangedEvents();
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1600,7 +1615,7 @@ AudioUnitPluginFormat::~AudioUnitPluginFormat()
|
||||
{
|
||||
}
|
||||
|
||||
void AudioUnitPluginFormat::findAllTypesForFile (OwnedArray <PluginDescription>& results,
|
||||
void AudioUnitPluginFormat::findAllTypesForFile (OwnedArray<PluginDescription>& results,
|
||||
const String& fileOrIdentifier)
|
||||
{
|
||||
if (! fileMightContainThisPluginType (fileOrIdentifier))
|
||||
|
||||
+2
-2
@@ -118,8 +118,8 @@ class LADSPAPluginInstance : public AudioPluginInstance
|
||||
{
|
||||
public:
|
||||
LADSPAPluginInstance (const LADSPAModuleHandle::Ptr& m)
|
||||
: plugin (nullptr), handle (nullptr), initialised (false),
|
||||
tempBuffer (1, 1), module (m)
|
||||
: module (m), plugin (nullptr), handle (nullptr),
|
||||
initialised (false), tempBuffer (1, 1)
|
||||
{
|
||||
++insideLADSPACallback;
|
||||
|
||||
|
||||
@@ -85,6 +85,18 @@ static Steinberg::Vst::TChar* toString (const juce::String& source) noexcept
|
||||
|
||||
|
||||
//==============================================================================
|
||||
static Steinberg::Vst::SpeakerArrangement getArrangementForBus (Steinberg::Vst::IAudioProcessor* processor,
|
||||
bool isInput, int busIndex)
|
||||
{
|
||||
Steinberg::Vst::SpeakerArrangement arrangement = Steinberg::Vst::SpeakerArr::kEmpty;
|
||||
|
||||
if (processor != nullptr)
|
||||
processor->getBusArrangement (isInput ? Steinberg::Vst::kInput : Steinberg::Vst::kOutput,
|
||||
(Steinberg::int32) busIndex, arrangement);
|
||||
|
||||
return arrangement;
|
||||
}
|
||||
|
||||
/** For the sake of simplicity, there can only be 1 arrangement type per channel count.
|
||||
i.e.: 4 channels == k31Cine OR k40Cine
|
||||
*/
|
||||
@@ -126,9 +138,9 @@ class ComSmartPtr
|
||||
{
|
||||
public:
|
||||
ComSmartPtr() noexcept : source (nullptr) {}
|
||||
ComSmartPtr (ObjectType* object) noexcept : source (object) { if (source != nullptr) source->addRef(); }
|
||||
ComSmartPtr (const ComSmartPtr& other) noexcept : source (other.source) { if (source != nullptr) source->addRef(); }
|
||||
~ComSmartPtr() { if (source != nullptr) source->release(); }
|
||||
ComSmartPtr (ObjectType* object, bool autoAddRef = true) noexcept : source (object) { if (source != nullptr && autoAddRef) source->addRef(); }
|
||||
ComSmartPtr (const ComSmartPtr& other) noexcept : source (other.source) { if (source != nullptr) source->addRef(); }
|
||||
~ComSmartPtr() { if (source != nullptr) source->release(); }
|
||||
|
||||
operator ObjectType*() const noexcept { return source; }
|
||||
ObjectType* get() const noexcept { return source; }
|
||||
@@ -341,7 +353,7 @@ namespace VST3BufferExchange
|
||||
Bus& bus,
|
||||
AudioSampleBuffer& buffer,
|
||||
int numChannels, int channelStartOffset,
|
||||
int sampleOffset = 0) noexcept
|
||||
int sampleOffset = 0)
|
||||
{
|
||||
const int channelEnd = numChannels + channelStartOffset;
|
||||
jassert (channelEnd >= 0 && channelEnd <= buffer.getNumChannels());
|
||||
@@ -356,37 +368,52 @@ namespace VST3BufferExchange
|
||||
vstBuffers.silenceFlags = 0;
|
||||
}
|
||||
|
||||
static void mapArrangementToBusses (int& channelIndexOffset, int index,
|
||||
Array<Steinberg::Vst::AudioBusBuffers>& result,
|
||||
BusMap& busMapToUse, Steinberg::Vst::SpeakerArrangement arrangement,
|
||||
AudioSampleBuffer& source)
|
||||
{
|
||||
const int numChansForBus = BigInteger ((juce::int64) arrangement).countNumberOfSetBits();
|
||||
|
||||
if (index >= result.size())
|
||||
result.add (Steinberg::Vst::AudioBusBuffers());
|
||||
|
||||
if (index >= busMapToUse.size())
|
||||
busMapToUse.add (Bus());
|
||||
|
||||
if (numChansForBus > 0)
|
||||
{
|
||||
associateBufferTo (result.getReference (index),
|
||||
busMapToUse.getReference (index),
|
||||
source, numChansForBus, channelIndexOffset);
|
||||
}
|
||||
|
||||
channelIndexOffset += numChansForBus;
|
||||
}
|
||||
|
||||
static void mapBufferToBusses (Array<Steinberg::Vst::AudioBusBuffers>& result, BusMap& busMapToUse,
|
||||
const Array<Steinberg::Vst::SpeakerArrangement>& arrangements,
|
||||
AudioSampleBuffer& source)
|
||||
{
|
||||
int channelIndexOffset = 0;
|
||||
|
||||
for (int i = 0; i < arrangements.size(); ++i)
|
||||
mapArrangementToBusses (channelIndexOffset, i, result, busMapToUse,
|
||||
arrangements.getUnchecked (i), source);
|
||||
}
|
||||
|
||||
static void mapBufferToBusses (Array<Steinberg::Vst::AudioBusBuffers>& result,
|
||||
Steinberg::Vst::IAudioProcessor& processor,
|
||||
BusMap& busMapToUse,
|
||||
bool isInput, int numBusses,
|
||||
BusMap& busMapToUse, bool isInput, int numBusses,
|
||||
AudioSampleBuffer& source)
|
||||
{
|
||||
int channelIndexOffset = 0;
|
||||
|
||||
for (int i = 0; i < numBusses; ++i)
|
||||
{
|
||||
Steinberg::Vst::SpeakerArrangement arrangement = 0;
|
||||
processor.getBusArrangement (isInput ? Steinberg::Vst::kInput : Steinberg::Vst::kOutput,
|
||||
(Steinberg::int32) i, arrangement);
|
||||
|
||||
const int numChansForBus = BigInteger ((juce::int64) arrangement).countNumberOfSetBits();
|
||||
|
||||
if (i >= result.size())
|
||||
result.add (Steinberg::Vst::AudioBusBuffers());
|
||||
|
||||
if (i >= busMapToUse.size())
|
||||
busMapToUse.add (Bus());
|
||||
|
||||
if (numChansForBus > 0)
|
||||
{
|
||||
associateBufferTo (result.getReference (i),
|
||||
busMapToUse.getReference (i),
|
||||
source, numChansForBus, channelIndexOffset);
|
||||
}
|
||||
|
||||
channelIndexOffset += numChansForBus;
|
||||
}
|
||||
mapArrangementToBusses (channelIndexOffset, i,
|
||||
result, busMapToUse,
|
||||
getArrangementForBus (&processor, isInput, i),
|
||||
source);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+365
-65
@@ -31,6 +31,7 @@
|
||||
#define JUCE_VST3HEADERS_INCLUDE_HEADERS_ONLY 1
|
||||
#endif
|
||||
|
||||
#include <map>
|
||||
#include "juce_VST3Headers.h"
|
||||
|
||||
#undef JUCE_VST3HEADERS_INCLUDE_HEADERS_ONLY
|
||||
@@ -111,6 +112,7 @@ static void createPluginDescription (PluginDescription& description,
|
||||
description.lastFileModTime = pluginFile.getLastModificationTime();
|
||||
description.manufacturerName = company;
|
||||
description.name = name;
|
||||
description.descriptiveName = name;
|
||||
description.pluginFormatName = "VST3";
|
||||
description.numInputChannels = numInputs;
|
||||
description.numOutputChannels = numOutputs;
|
||||
@@ -378,32 +380,65 @@ public:
|
||||
|
||||
FUnknown* getFUnknown() { return static_cast<Vst::IComponentHandler*> (this); }
|
||||
|
||||
static bool hasFlag (Steinberg::int32 source, Steinberg::int32 flag) noexcept
|
||||
{
|
||||
return (source & flag) == flag;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
tresult PLUGIN_API beginEdit (Vst::ParamID) override
|
||||
tresult PLUGIN_API beginEdit (Vst::ParamID paramID) override
|
||||
{
|
||||
// XXX todo..
|
||||
return kResultFalse;
|
||||
const int index = getIndexOfParamID (paramID);
|
||||
|
||||
if (index < 0)
|
||||
return kResultFalse;
|
||||
|
||||
owner->beginParameterChangeGesture (index);
|
||||
return kResultTrue;
|
||||
}
|
||||
|
||||
tresult PLUGIN_API performEdit (Vst::ParamID id, Vst::ParamValue valueNormalized) override
|
||||
tresult PLUGIN_API performEdit (Vst::ParamID paramID, Vst::ParamValue valueNormalized) override
|
||||
{
|
||||
if (owner != nullptr)
|
||||
return owner->editController->setParamNormalized (id, valueNormalized);
|
||||
const int index = getIndexOfParamID (paramID);
|
||||
|
||||
return kResultFalse;
|
||||
if (index < 0)
|
||||
return kResultFalse;
|
||||
|
||||
owner->sendParamChangeMessageToListeners (index, (float) valueNormalized);
|
||||
return owner->editController->setParamNormalized (paramID, valueNormalized);
|
||||
}
|
||||
|
||||
tresult PLUGIN_API endEdit (Vst::ParamID) override
|
||||
tresult PLUGIN_API endEdit (Vst::ParamID paramID) override
|
||||
{
|
||||
// XXX todo..
|
||||
return kResultFalse;
|
||||
const int index = getIndexOfParamID (paramID);
|
||||
|
||||
if (index < 0)
|
||||
return kResultFalse;
|
||||
|
||||
owner->endParameterChangeGesture (index);
|
||||
return kResultTrue;
|
||||
}
|
||||
|
||||
tresult PLUGIN_API restartComponent (Steinberg::int32) override
|
||||
tresult PLUGIN_API restartComponent (Steinberg::int32 flags) override
|
||||
{
|
||||
if (owner != nullptr)
|
||||
{
|
||||
owner->reset();
|
||||
if (hasFlag (flags, Vst::kReloadComponent))
|
||||
owner->reset();
|
||||
|
||||
if (hasFlag (flags, Vst::kIoChanged))
|
||||
{
|
||||
const double sampleRate = owner->getSampleRate();
|
||||
const int blockSize = owner->getBlockSize();
|
||||
|
||||
owner->prepareToPlay (sampleRate >= 8000 ? sampleRate : 44100.0,
|
||||
blockSize > 0 ? blockSize : 1024);
|
||||
}
|
||||
|
||||
if (hasFlag (flags, Vst::kLatencyChanged))
|
||||
if (owner->processor != nullptr)
|
||||
owner->setLatencySamples (jmax (0, (int) owner->processor->getLatencySamples()));
|
||||
|
||||
owner->updateHostDisplay();
|
||||
return kResultTrue;
|
||||
}
|
||||
@@ -437,9 +472,171 @@ public:
|
||||
return kResultFalse;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
class ContextMenu : public Vst::IContextMenu
|
||||
{
|
||||
public:
|
||||
ContextMenu (VST3PluginInstance& pluginInstance) : owner (pluginInstance) {}
|
||||
virtual ~ContextMenu() {}
|
||||
|
||||
JUCE_DECLARE_VST3_COM_REF_METHODS
|
||||
JUCE_DECLARE_VST3_COM_QUERY_METHODS
|
||||
|
||||
Steinberg::int32 PLUGIN_API getItemCount() override { return (Steinberg::int32) items.size(); }
|
||||
|
||||
tresult PLUGIN_API addItem (const Item& item, IContextMenuTarget* target) override
|
||||
{
|
||||
jassert (target != nullptr);
|
||||
|
||||
ItemAndTarget newItem;
|
||||
newItem.item = item;
|
||||
newItem.target = target;
|
||||
|
||||
items.add (newItem);
|
||||
return kResultOk;
|
||||
}
|
||||
|
||||
tresult PLUGIN_API removeItem (const Item& toRemove, IContextMenuTarget* target) override
|
||||
{
|
||||
for (int i = items.size(); --i >= 0;)
|
||||
{
|
||||
ItemAndTarget& item = items.getReference(i);
|
||||
|
||||
if (item.item.tag == toRemove.tag && item.target == target)
|
||||
items.remove (i);
|
||||
}
|
||||
|
||||
return kResultOk;
|
||||
}
|
||||
|
||||
tresult PLUGIN_API getItem (Steinberg::int32 tag, Item& result, IContextMenuTarget** target) override
|
||||
{
|
||||
for (int i = 0; i < items.size(); ++i)
|
||||
{
|
||||
const ItemAndTarget& item = items.getReference(i);
|
||||
|
||||
if (item.item.tag == tag)
|
||||
{
|
||||
result = item.item;
|
||||
|
||||
if (target != nullptr)
|
||||
*target = item.target;
|
||||
|
||||
return kResultTrue;
|
||||
}
|
||||
}
|
||||
|
||||
zerostruct (result);
|
||||
return kResultFalse;
|
||||
}
|
||||
|
||||
tresult PLUGIN_API popup (Steinberg::UCoord x, Steinberg::UCoord y) override
|
||||
{
|
||||
Array<const Item*> subItemStack;
|
||||
OwnedArray<PopupMenu> menuStack;
|
||||
PopupMenu* topLevelMenu = menuStack.add (new PopupMenu());
|
||||
|
||||
for (int i = 0; i < items.size(); ++i)
|
||||
{
|
||||
const Item& item = items.getReference (i).item;
|
||||
|
||||
PopupMenu* menuToUse = menuStack.getLast();
|
||||
|
||||
if (hasFlag (item.flags, Item::kIsGroupStart & ~Item::kIsDisabled))
|
||||
{
|
||||
subItemStack.add (&item);
|
||||
menuStack.add (new PopupMenu());
|
||||
}
|
||||
else if (hasFlag (item.flags, Item::kIsGroupEnd))
|
||||
{
|
||||
if (const Item* subItem = subItemStack.getLast())
|
||||
{
|
||||
if (PopupMenu* m = menuStack [menuStack.size() - 2])
|
||||
m->addSubMenu (toString (subItem->name), *menuToUse,
|
||||
! hasFlag (subItem->flags, Item::kIsDisabled),
|
||||
nullptr,
|
||||
hasFlag (subItem->flags, Item::kIsChecked));
|
||||
|
||||
menuStack.removeLast (1);
|
||||
subItemStack.removeLast (1);
|
||||
}
|
||||
}
|
||||
else if (hasFlag (item.flags, Item::kIsSeparator))
|
||||
{
|
||||
menuToUse->addSeparator();
|
||||
}
|
||||
else
|
||||
{
|
||||
menuToUse->addItem (item.tag != 0 ? (int) item.tag : (int) zeroTagReplacement,
|
||||
toString (item.name),
|
||||
! hasFlag (item.flags, Item::kIsDisabled),
|
||||
hasFlag (item.flags, Item::kIsChecked));
|
||||
}
|
||||
}
|
||||
|
||||
PopupMenu::Options options;
|
||||
|
||||
if (AudioProcessorEditor* ed = owner.getActiveEditor())
|
||||
options = options.withTargetScreenArea (ed->getScreenBounds().translated ((int) x, (int) y).withSize (1, 1));
|
||||
|
||||
#if JUCE_MODAL_LOOPS_PERMITTED
|
||||
// Unfortunately, Steinberg's docs explicitly say this should be modal..
|
||||
handleResult (topLevelMenu->showMenu (options));
|
||||
#else
|
||||
topLevelMenu->showMenuAsync (options, ModalCallbackFunction::create (menuFinished, ComSmartPtr<ContextMenu> (this)));
|
||||
#endif
|
||||
|
||||
return kResultOk;
|
||||
}
|
||||
|
||||
#if ! JUCE_MODAL_LOOPS_PERMITTED
|
||||
static void menuFinished (int modalResult, ComSmartPtr<ContextMenu> menu) { menu->handleResult (modalResult); }
|
||||
#endif
|
||||
|
||||
private:
|
||||
enum { zeroTagReplacement = 0x7fffffff };
|
||||
|
||||
Atomic<int> refCount;
|
||||
VST3PluginInstance& owner;
|
||||
|
||||
struct ItemAndTarget
|
||||
{
|
||||
Item item;
|
||||
ComSmartPtr<IContextMenuTarget> target;
|
||||
};
|
||||
|
||||
Array<ItemAndTarget> items;
|
||||
|
||||
void handleResult (int result)
|
||||
{
|
||||
if (result == 0)
|
||||
return;
|
||||
|
||||
if (result == zeroTagReplacement)
|
||||
result = 0;
|
||||
|
||||
for (int i = 0; i < items.size(); ++i)
|
||||
{
|
||||
const ItemAndTarget& item = items.getReference(i);
|
||||
|
||||
if ((int) item.item.tag == result)
|
||||
{
|
||||
if (item.target != nullptr)
|
||||
item.target->executeMenuItem ((Steinberg::int32) result);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ContextMenu)
|
||||
};
|
||||
|
||||
Vst::IContextMenu* PLUGIN_API createContextMenu (IPlugView*, const Vst::ParamID*) override
|
||||
{
|
||||
jassertfalse;
|
||||
if (owner != nullptr)
|
||||
return new ContextMenu (*owner);
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -549,9 +746,42 @@ public:
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
Atomic<int32> refCount;
|
||||
VST3PluginInstance* const owner;
|
||||
Atomic<int> refCount;
|
||||
String appName;
|
||||
VST3PluginInstance* owner;
|
||||
|
||||
typedef std::map<Vst::ParamID, int> ParamMapType;
|
||||
ParamMapType paramToIndexMap;
|
||||
|
||||
int getIndexOfParamID (Vst::ParamID paramID)
|
||||
{
|
||||
if (owner == nullptr || owner->editController == nullptr)
|
||||
return -1;
|
||||
|
||||
int result = getMappedParamID (paramID);
|
||||
|
||||
if (result < 0)
|
||||
{
|
||||
const int numParams = owner->editController->getParameterCount();
|
||||
|
||||
for (int i = 0; i < numParams; ++i)
|
||||
{
|
||||
Vst::ParameterInfo paramInfo;
|
||||
owner->editController->getParameterInfo (i, paramInfo);
|
||||
paramToIndexMap[paramInfo.id] = i;
|
||||
}
|
||||
|
||||
result = getMappedParamID (paramID);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int getMappedParamID (Vst::ParamID paramID)
|
||||
{
|
||||
const ParamMapType::iterator it (paramToIndexMap.find (paramID));
|
||||
return it != paramToIndexMap.end() ? it->second : -1;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
class Message : public Vst::IMessage
|
||||
@@ -577,9 +807,9 @@ private:
|
||||
JUCE_DECLARE_VST3_COM_REF_METHODS
|
||||
JUCE_DECLARE_VST3_COM_QUERY_METHODS
|
||||
|
||||
FIDString PLUGIN_API getMessageID() { return messageId.toRawUTF8(); }
|
||||
void PLUGIN_API setMessageID (FIDString id) { messageId = toString (id); }
|
||||
Vst::IAttributeList* PLUGIN_API getAttributes() { return attributeList; }
|
||||
FIDString PLUGIN_API getMessageID() override { return messageId.toRawUTF8(); }
|
||||
void PLUGIN_API setMessageID (FIDString id) override { messageId = toString (id); }
|
||||
Vst::IAttributeList* PLUGIN_API getAttributes() override { return attributeList; }
|
||||
|
||||
var value;
|
||||
|
||||
@@ -587,7 +817,7 @@ private:
|
||||
VST3HostContext& owner;
|
||||
ComSmartPtr<Vst::IAttributeList> attributeList;
|
||||
String messageId;
|
||||
Atomic<int32> refCount;
|
||||
Atomic<int> refCount;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Message)
|
||||
};
|
||||
@@ -715,7 +945,7 @@ private:
|
||||
|
||||
private:
|
||||
VST3HostContext* owner;
|
||||
Atomic<int32> refCount;
|
||||
Atomic<int> refCount;
|
||||
|
||||
//==============================================================================
|
||||
template<typename Type>
|
||||
@@ -1195,7 +1425,8 @@ public:
|
||||
VST3PluginWindow (AudioProcessor* owner, IPlugView* pluginView)
|
||||
: AudioProcessorEditor (owner),
|
||||
ComponentMovementWatcher (this),
|
||||
view (pluginView),
|
||||
refCount (1),
|
||||
view (pluginView, false),
|
||||
pluginHandle (nullptr),
|
||||
recursiveResize (false)
|
||||
{
|
||||
@@ -1213,7 +1444,9 @@ public:
|
||||
~VST3PluginWindow()
|
||||
{
|
||||
warnOnFailure (view->removed());
|
||||
getAudioProcessor()->editorBeingDeleted (this);
|
||||
warnOnFailure (view->setFrame (nullptr));
|
||||
|
||||
processor.editorBeingDeleted (this);
|
||||
|
||||
#if JUCE_MAC
|
||||
dummyComponent.setView (nullptr);
|
||||
@@ -1266,20 +1499,32 @@ public:
|
||||
{
|
||||
rect.right = (Steinberg::int32) getWidth();
|
||||
rect.bottom = (Steinberg::int32) getHeight();
|
||||
view->checkSizeConstraint (&rect);
|
||||
|
||||
setSize ((int) rect.getWidth(), (int) rect.getHeight());
|
||||
|
||||
#if JUCE_WINDOWS
|
||||
SetWindowPos (pluginHandle, 0,
|
||||
pos.x, pos.y, rect.getWidth(), rect.getHeight(),
|
||||
isVisible() ? SWP_SHOWWINDOW : SWP_HIDEWINDOW);
|
||||
#elif JUCE_MAC
|
||||
dummyComponent.setBounds (getLocalBounds());
|
||||
#endif
|
||||
|
||||
view->onSize (&rect);
|
||||
}
|
||||
else
|
||||
{
|
||||
warnOnFailure (view->getSize (&rect));
|
||||
}
|
||||
|
||||
#if JUCE_WINDOWS
|
||||
SetWindowPos (pluginHandle, 0,
|
||||
pos.x, pos.y, rect.getWidth(), rect.getHeight(),
|
||||
isVisible() ? SWP_SHOWWINDOW : SWP_HIDEWINDOW);
|
||||
#elif JUCE_MAC
|
||||
dummyComponent.setBounds (0, 0, (int) rect.getWidth(), (int) rect.getHeight());
|
||||
#endif
|
||||
#if JUCE_WINDOWS
|
||||
SetWindowPos (pluginHandle, 0,
|
||||
pos.x, pos.y, rect.getWidth(), rect.getHeight(),
|
||||
isVisible() ? SWP_SHOWWINDOW : SWP_HIDEWINDOW);
|
||||
#elif JUCE_MAC
|
||||
dummyComponent.setBounds (0, 0, (int) rect.getWidth(), (int) rect.getHeight());
|
||||
#endif
|
||||
}
|
||||
|
||||
// Some plugins don't update their cursor correctly when mousing out the window
|
||||
Desktop::getInstance().getMainMouseSource().forceMouseCursorUpdate();
|
||||
@@ -1364,7 +1609,7 @@ private:
|
||||
if (peer != nullptr)
|
||||
pluginHandle = (HandleFormat) peer->getNativeHandle();
|
||||
#elif JUCE_MAC
|
||||
dummyComponent.setBounds (getBounds().withZeroOrigin());
|
||||
dummyComponent.setBounds (getLocalBounds());
|
||||
addAndMakeVisible (dummyComponent);
|
||||
pluginHandle = (NSView*) dummyComponent.getView();
|
||||
jassert (pluginHandle != nil);
|
||||
@@ -1391,7 +1636,8 @@ public:
|
||||
midiInputs (new MidiEventList()),
|
||||
midiOutputs (new MidiEventList()),
|
||||
isComponentInitialised (false),
|
||||
isControllerInitialised (false)
|
||||
isControllerInitialised (false),
|
||||
isActive (false)
|
||||
{
|
||||
host = new VST3HostContext (this);
|
||||
}
|
||||
@@ -1413,7 +1659,6 @@ public:
|
||||
if (isControllerInitialised) editController->terminate();
|
||||
if (isComponentInitialised) component->terminate();
|
||||
|
||||
//Deletion order appears to matter:
|
||||
componentConnection = nullptr;
|
||||
editControllerConnection = nullptr;
|
||||
unitData = nullptr;
|
||||
@@ -1425,6 +1670,8 @@ public:
|
||||
editController2 = nullptr;
|
||||
editController = nullptr;
|
||||
component = nullptr;
|
||||
host = nullptr;
|
||||
module = nullptr;
|
||||
}
|
||||
|
||||
bool initialise()
|
||||
@@ -1478,8 +1725,27 @@ public:
|
||||
return module != nullptr ? module->name : String::empty;
|
||||
}
|
||||
|
||||
void repopulateArrangements()
|
||||
{
|
||||
inputArrangements.clearQuick();
|
||||
outputArrangements.clearQuick();
|
||||
|
||||
// NB: Some plugins need a valid arrangement despite specifying 0 for their I/O busses
|
||||
for (int i = 0; i < jmax (1, numInputAudioBusses); ++i)
|
||||
inputArrangements.add (getArrangementForBus (processor, true, i));
|
||||
|
||||
for (int i = 0; i < jmax (1, numOutputAudioBusses); ++i)
|
||||
outputArrangements.add (getArrangementForBus (processor, false, i));
|
||||
}
|
||||
|
||||
void prepareToPlay (double sampleRate, int estimatedSamplesPerBlock) override
|
||||
{
|
||||
// Avoid redundantly calling things like setActive, which can be a heavy-duty call for some plugins:
|
||||
if (isActive
|
||||
&& getSampleRate() == sampleRate
|
||||
&& getBlockSize() == estimatedSamplesPerBlock)
|
||||
return;
|
||||
|
||||
using namespace Vst;
|
||||
|
||||
ProcessSetup setup;
|
||||
@@ -1495,20 +1761,25 @@ public:
|
||||
|
||||
editController->setComponentHandler (host);
|
||||
|
||||
Array<SpeakerArrangement> inArrangements, outArrangements;
|
||||
if (inputArrangements.size() <= 0 || outputArrangements.size() <= 0)
|
||||
repopulateArrangements();
|
||||
|
||||
for (int i = 0; i < numInputAudioBusses; ++i)
|
||||
inArrangements.add (getArrangementForNumChannels (jmax (0, (int) getBusInfo (true, true, i).channelCount)));
|
||||
|
||||
for (int i = 0; i < numOutputAudioBusses; ++i)
|
||||
outArrangements.add (getArrangementForNumChannels (jmax (0, (int) getBusInfo (false, true, i).channelCount)));
|
||||
|
||||
warnOnFailure (processor->setBusArrangements (inArrangements.getRawDataPointer(), numInputAudioBusses,
|
||||
outArrangements.getRawDataPointer(), numOutputAudioBusses));
|
||||
warnOnFailure (processor->setBusArrangements (inputArrangements.getRawDataPointer(), numInputAudioBusses,
|
||||
outputArrangements.getRawDataPointer(), numOutputAudioBusses));
|
||||
|
||||
// Update the num. busses in case the configuration has been modified by the plugin. (May affect number of channels!):
|
||||
numInputAudioBusses = getNumSingleDirectionBussesFor (component, true, true);
|
||||
numOutputAudioBusses = getNumSingleDirectionBussesFor (component, false, true);
|
||||
const int newNumInputAudioBusses = getNumSingleDirectionBussesFor (component, true, true);
|
||||
const int newNumOutputAudioBusses = getNumSingleDirectionBussesFor (component, false, true);
|
||||
|
||||
// Repopulate arrangements if the number of busses have changed:
|
||||
if (numInputAudioBusses != newNumInputAudioBusses
|
||||
|| numOutputAudioBusses != newNumOutputAudioBusses)
|
||||
{
|
||||
numInputAudioBusses = newNumInputAudioBusses;
|
||||
numOutputAudioBusses = newNumOutputAudioBusses;
|
||||
|
||||
repopulateArrangements();
|
||||
}
|
||||
|
||||
// Needed for having the same sample rate in processBlock(); some plugins need this!
|
||||
setPlayConfigDetails (getNumSingleDirectionChannelsFor (component, true, true),
|
||||
@@ -1517,21 +1788,30 @@ public:
|
||||
|
||||
setStateForAllBusses (true);
|
||||
|
||||
setLatencySamples (jmax (0, (int) processor->getLatencySamples()));
|
||||
|
||||
warnOnFailure (component->setActive (true));
|
||||
warnOnFailure (processor->setProcessing (true));
|
||||
|
||||
isActive = true;
|
||||
}
|
||||
|
||||
void releaseResources() override
|
||||
{
|
||||
if (! isActive)
|
||||
return; // Avoids redundantly calling things like setActive
|
||||
|
||||
JUCE_TRY
|
||||
{
|
||||
isActive = false;
|
||||
|
||||
setStateForAllBusses (false);
|
||||
|
||||
if (processor != nullptr)
|
||||
processor->setProcessing (false);
|
||||
warnOnFailure (processor->setProcessing (false));
|
||||
|
||||
if (component != nullptr)
|
||||
component->setActive (false);
|
||||
warnOnFailure (component->setActive (false));
|
||||
}
|
||||
JUCE_CATCH_ALL_ASSERT
|
||||
}
|
||||
@@ -1540,7 +1820,8 @@ public:
|
||||
{
|
||||
using namespace Vst;
|
||||
|
||||
if (processor != nullptr
|
||||
if (isActive
|
||||
&& processor != nullptr
|
||||
&& processor->canProcessSampleSize (kSample32) == kResultTrue)
|
||||
{
|
||||
const int numSamples = buffer.getNumSamples();
|
||||
@@ -1612,15 +1893,22 @@ public:
|
||||
//==============================================================================
|
||||
bool silenceInProducesSilenceOut() const override
|
||||
{
|
||||
return processor == nullptr;
|
||||
if (processor != nullptr)
|
||||
return processor->getTailSamples() == Vst::kNoTail;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/** May return a negative value as a means of informing us that the plugin has "infinite tail," or 0 for "no tail." */
|
||||
double getTailLengthSeconds() const override
|
||||
{
|
||||
if (processor != nullptr)
|
||||
return (double) jmin ((int) jmax ((Steinberg::uint32) 0, processor->getTailSamples()), 0x7fffffff)
|
||||
* getSampleRate();
|
||||
{
|
||||
const double sampleRate = getSampleRate();
|
||||
|
||||
if (sampleRate > 0.0)
|
||||
return jlimit (0, 0x7fffffff, (int) processor->getTailSamples()) / sampleRate;
|
||||
}
|
||||
|
||||
return 0.0;
|
||||
}
|
||||
@@ -1640,7 +1928,7 @@ public:
|
||||
if (getActiveEditor() != nullptr)
|
||||
return true;
|
||||
|
||||
ComSmartPtr<IPlugView> view (tryCreatingView());
|
||||
ComSmartPtr<IPlugView> view (tryCreatingView(), false);
|
||||
return view != nullptr;
|
||||
}
|
||||
|
||||
@@ -1706,6 +1994,16 @@ public:
|
||||
return toString (result);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void reset() override
|
||||
{
|
||||
if (component != nullptr)
|
||||
{
|
||||
component->setActive (false);
|
||||
component->setActive (true);
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void getStateInformation (MemoryBlock& destData) override
|
||||
{
|
||||
@@ -1785,6 +2083,7 @@ private:
|
||||
as very poorly specified by the Steinberg SDK
|
||||
*/
|
||||
int numInputAudioBusses, numOutputAudioBusses;
|
||||
Array<Vst::SpeakerArrangement> inputArrangements, outputArrangements; // Caching to improve performance and to avoid possible non-thread-safe calls to getBusArrangements().
|
||||
VST3BufferExchange::BusMap inputBusMap, outputBusMap;
|
||||
Array<Vst::AudioBusBuffers> inputBusses, outputBusses;
|
||||
|
||||
@@ -1813,7 +2112,11 @@ private:
|
||||
MemoryBlock mem;
|
||||
|
||||
if (mem.fromBase64Encoding (state->getAllSubText()))
|
||||
stream = new Steinberg::MemoryStream (mem.getData(), (TSize) mem.getSize());
|
||||
{
|
||||
stream = new Steinberg::MemoryStream();
|
||||
stream->setSize ((TSize) mem.getSize());
|
||||
mem.copyTo (stream->getData(), 0, mem.getSize());
|
||||
}
|
||||
}
|
||||
|
||||
return stream;
|
||||
@@ -1829,21 +2132,21 @@ private:
|
||||
JUCE_DECLARE_VST3_COM_REF_METHODS
|
||||
JUCE_DECLARE_VST3_COM_QUERY_METHODS
|
||||
|
||||
Steinberg::int32 PLUGIN_API getParameterCount() { return 0; }
|
||||
Steinberg::int32 PLUGIN_API getParameterCount() override { return 0; }
|
||||
|
||||
Vst::IParamValueQueue* PLUGIN_API getParameterData (Steinberg::int32)
|
||||
Vst::IParamValueQueue* PLUGIN_API getParameterData (Steinberg::int32) override
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Vst::IParamValueQueue* PLUGIN_API addParameterData (const Vst::ParamID&, Steinberg::int32& index)
|
||||
Vst::IParamValueQueue* PLUGIN_API addParameterData (const Vst::ParamID&, Steinberg::int32& index) override
|
||||
{
|
||||
index = 0;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
Atomic<int32> refCount;
|
||||
Atomic<int> refCount;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ParameterChangeList)
|
||||
};
|
||||
@@ -1851,7 +2154,7 @@ private:
|
||||
ComSmartPtr<ParameterChangeList> inputParameterChanges, outputParameterChanges;
|
||||
ComSmartPtr<MidiEventList> midiInputs, midiOutputs;
|
||||
Vst::ProcessContext timingInfo; //< Only use this in processBlock()!
|
||||
bool isComponentInitialised, isControllerInitialised;
|
||||
bool isComponentInitialised, isControllerInitialised, isActive;
|
||||
|
||||
//==============================================================================
|
||||
bool fetchComponentAndController (IPluginFactory* factory, const Steinberg::int32 numClasses)
|
||||
@@ -2031,11 +2334,11 @@ private:
|
||||
Vst::BusInfo getBusInfo (bool forInput, bool forAudio, int index = 0) const
|
||||
{
|
||||
Vst::BusInfo busInfo;
|
||||
busInfo.mediaType = forAudio ? Vst::kAudio : Vst::kEvent;
|
||||
busInfo.direction = forInput ? Vst::kInput : Vst::kOutput;
|
||||
|
||||
component->getBusInfo (forAudio ? Vst::kAudio : Vst::kEvent,
|
||||
forInput ? Vst::kInput : Vst::kOutput,
|
||||
component->getBusInfo (busInfo.mediaType, busInfo.direction,
|
||||
(Steinberg::int32) index, busInfo);
|
||||
|
||||
return busInfo;
|
||||
}
|
||||
|
||||
@@ -2056,11 +2359,8 @@ private:
|
||||
{
|
||||
using namespace VST3BufferExchange;
|
||||
|
||||
mapBufferToBusses (inputBusses, *processor, inputBusMap,
|
||||
true, numInputAudioBusses, buffer);
|
||||
|
||||
mapBufferToBusses (outputBusses, *processor, outputBusMap,
|
||||
false, numOutputAudioBusses, buffer);
|
||||
mapBufferToBusses (inputBusses, inputBusMap, inputArrangements, buffer);
|
||||
mapBufferToBusses (outputBusses, outputBusMap, outputArrangements, buffer);
|
||||
|
||||
destination.inputs = inputBusses.getRawDataPointer();
|
||||
destination.outputs = outputBusses.getRawDataPointer();
|
||||
|
||||
+186
-202
@@ -29,13 +29,6 @@
|
||||
#include "../../juce_gui_extra/native/juce_mac_CarbonViewWrapperComponent.h"
|
||||
#endif
|
||||
|
||||
#if JUCE_MAC
|
||||
static bool makeFSRefFromPath (FSRef* destFSRef, const String& path)
|
||||
{
|
||||
return FSPathMakeRef (reinterpret_cast<const UInt8*> (path.toRawUTF8()), destFSRef, 0) == noErr;
|
||||
}
|
||||
#endif
|
||||
|
||||
//==============================================================================
|
||||
#undef PRAGMA_ALIGN_SUPPORTED
|
||||
#define VST_FORCE_DEPRECATED 0
|
||||
@@ -84,74 +77,68 @@
|
||||
#endif
|
||||
|
||||
//==============================================================================
|
||||
const int fxbVersionNum = 1;
|
||||
|
||||
struct fxProgram
|
||||
{
|
||||
VstInt32 chunkMagic; // 'CcnK'
|
||||
VstInt32 byteSize; // of this chunk, excl. magic + byteSize
|
||||
VstInt32 fxMagic; // 'FxCk'
|
||||
VstInt32 version;
|
||||
VstInt32 fxID; // fx unique id
|
||||
VstInt32 fxVersion;
|
||||
VstInt32 numParams;
|
||||
char prgName[28];
|
||||
float params[1]; // variable no. of parameters
|
||||
};
|
||||
|
||||
struct fxSet
|
||||
{
|
||||
VstInt32 chunkMagic; // 'CcnK'
|
||||
VstInt32 byteSize; // of this chunk, excl. magic + byteSize
|
||||
VstInt32 fxMagic; // 'FxBk'
|
||||
VstInt32 version;
|
||||
VstInt32 fxID; // fx unique id
|
||||
VstInt32 fxVersion;
|
||||
VstInt32 numPrograms;
|
||||
char future[128];
|
||||
fxProgram programs[1]; // variable no. of programs
|
||||
};
|
||||
|
||||
struct fxChunkSet
|
||||
{
|
||||
VstInt32 chunkMagic; // 'CcnK'
|
||||
VstInt32 byteSize; // of this chunk, excl. magic + byteSize
|
||||
VstInt32 fxMagic; // 'FxCh', 'FPCh', or 'FBCh'
|
||||
VstInt32 version;
|
||||
VstInt32 fxID; // fx unique id
|
||||
VstInt32 fxVersion;
|
||||
VstInt32 numPrograms;
|
||||
char future[128];
|
||||
VstInt32 chunkSize;
|
||||
char chunk[8]; // variable
|
||||
};
|
||||
|
||||
struct fxProgramSet
|
||||
{
|
||||
VstInt32 chunkMagic; // 'CcnK'
|
||||
VstInt32 byteSize; // of this chunk, excl. magic + byteSize
|
||||
VstInt32 fxMagic; // 'FxCh', 'FPCh', or 'FBCh'
|
||||
VstInt32 version;
|
||||
VstInt32 fxID; // fx unique id
|
||||
VstInt32 fxVersion;
|
||||
VstInt32 numPrograms;
|
||||
char name[28];
|
||||
VstInt32 chunkSize;
|
||||
char chunk[8]; // variable
|
||||
};
|
||||
|
||||
namespace
|
||||
{
|
||||
VstInt32 vst_swap (const VstInt32 x) noexcept
|
||||
{
|
||||
#ifdef JUCE_LITTLE_ENDIAN
|
||||
return (VstInt32) ByteOrder::swap ((uint32) x);
|
||||
#else
|
||||
return x;
|
||||
#endif
|
||||
}
|
||||
const int fxbVersionNum = 1;
|
||||
|
||||
float vst_swapFloat (const float x) noexcept
|
||||
struct fxProgram
|
||||
{
|
||||
VstInt32 chunkMagic; // 'CcnK'
|
||||
VstInt32 byteSize; // of this chunk, excl. magic + byteSize
|
||||
VstInt32 fxMagic; // 'FxCk'
|
||||
VstInt32 version;
|
||||
VstInt32 fxID; // fx unique id
|
||||
VstInt32 fxVersion;
|
||||
VstInt32 numParams;
|
||||
char prgName[28];
|
||||
float params[1]; // variable no. of parameters
|
||||
};
|
||||
|
||||
struct fxSet
|
||||
{
|
||||
VstInt32 chunkMagic; // 'CcnK'
|
||||
VstInt32 byteSize; // of this chunk, excl. magic + byteSize
|
||||
VstInt32 fxMagic; // 'FxBk'
|
||||
VstInt32 version;
|
||||
VstInt32 fxID; // fx unique id
|
||||
VstInt32 fxVersion;
|
||||
VstInt32 numPrograms;
|
||||
char future[128];
|
||||
fxProgram programs[1]; // variable no. of programs
|
||||
};
|
||||
|
||||
struct fxChunkSet
|
||||
{
|
||||
VstInt32 chunkMagic; // 'CcnK'
|
||||
VstInt32 byteSize; // of this chunk, excl. magic + byteSize
|
||||
VstInt32 fxMagic; // 'FxCh', 'FPCh', or 'FBCh'
|
||||
VstInt32 version;
|
||||
VstInt32 fxID; // fx unique id
|
||||
VstInt32 fxVersion;
|
||||
VstInt32 numPrograms;
|
||||
char future[128];
|
||||
VstInt32 chunkSize;
|
||||
char chunk[8]; // variable
|
||||
};
|
||||
|
||||
struct fxProgramSet
|
||||
{
|
||||
VstInt32 chunkMagic; // 'CcnK'
|
||||
VstInt32 byteSize; // of this chunk, excl. magic + byteSize
|
||||
VstInt32 fxMagic; // 'FxCh', 'FPCh', or 'FBCh'
|
||||
VstInt32 version;
|
||||
VstInt32 fxID; // fx unique id
|
||||
VstInt32 fxVersion;
|
||||
VstInt32 numPrograms;
|
||||
char name[28];
|
||||
VstInt32 chunkSize;
|
||||
char chunk[8]; // variable
|
||||
};
|
||||
|
||||
static VstInt32 fxbName (const char* name) noexcept { return (VstInt32) ByteOrder::bigEndianInt (name); }
|
||||
static VstInt32 fxbSwap (const VstInt32 x) noexcept { return (VstInt32) ByteOrder::swapIfLittleEndian ((uint32) x); }
|
||||
|
||||
static float fxbSwapFloat (const float x) noexcept
|
||||
{
|
||||
#ifdef JUCE_LITTLE_ENDIAN
|
||||
union { uint32 asInt; float asFloat; } n;
|
||||
@@ -162,8 +149,12 @@ namespace
|
||||
return x;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
double getVSTHostTimeNanoseconds()
|
||||
//==============================================================================
|
||||
namespace
|
||||
{
|
||||
static double getVSTHostTimeNanoseconds() noexcept
|
||||
{
|
||||
#if JUCE_WINDOWS
|
||||
return timeGetTime() * 1000000.0;
|
||||
@@ -177,40 +168,52 @@ namespace
|
||||
return micro.lo * 1000.0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int shellUIDToCreate = 0;
|
||||
static int insideVSTCallback = 0;
|
||||
|
||||
struct IdleCallRecursionPreventer
|
||||
{
|
||||
IdleCallRecursionPreventer() : isMessageThread (MessageManager::getInstance()->isThisTheMessageThread())
|
||||
{
|
||||
if (isMessageThread)
|
||||
++insideVSTCallback;
|
||||
}
|
||||
|
||||
~IdleCallRecursionPreventer()
|
||||
{
|
||||
if (isMessageThread)
|
||||
--insideVSTCallback;
|
||||
}
|
||||
|
||||
const bool isMessageThread;
|
||||
JUCE_DECLARE_NON_COPYABLE (IdleCallRecursionPreventer)
|
||||
};
|
||||
|
||||
#if JUCE_MAC
|
||||
static bool makeFSRefFromPath (FSRef* destFSRef, const String& path)
|
||||
{
|
||||
return FSPathMakeRef (reinterpret_cast<const UInt8*> (path.toRawUTF8()), destFSRef, 0) == noErr;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if JUCE_MAC && JUCE_PPC
|
||||
static void* newCFMFromMachO (void* const machofp) noexcept
|
||||
{
|
||||
void* result = (void*) new char[8];
|
||||
|
||||
((void**) result)[0] = machofp;
|
||||
((void**) result)[1] = result;
|
||||
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
typedef AEffect* (VSTCALLBACK *MainCall) (audioMasterCallback);
|
||||
|
||||
static VstIntPtr VSTCALLBACK audioMaster (AEffect* effect, VstInt32 opcode, VstInt32 index, VstIntPtr value, void* ptr, float opt);
|
||||
|
||||
static int shellUIDToCreate = 0;
|
||||
static int insideVSTCallback = 0;
|
||||
|
||||
class IdleCallRecursionPreventer
|
||||
{
|
||||
public:
|
||||
IdleCallRecursionPreventer()
|
||||
: isMessageThread (MessageManager::getInstance()->isThisTheMessageThread())
|
||||
{
|
||||
if (isMessageThread)
|
||||
++insideVSTCallback;
|
||||
}
|
||||
|
||||
~IdleCallRecursionPreventer()
|
||||
{
|
||||
if (isMessageThread)
|
||||
--insideVSTCallback;
|
||||
}
|
||||
|
||||
private:
|
||||
const bool isMessageThread;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE (IdleCallRecursionPreventer)
|
||||
};
|
||||
|
||||
class VSTPluginWindow;
|
||||
|
||||
//==============================================================================
|
||||
// Change this to disable logging of various VST activities
|
||||
#ifndef VST_LOGGING
|
||||
@@ -223,27 +226,12 @@ class VSTPluginWindow;
|
||||
#define JUCE_VST_LOG(a)
|
||||
#endif
|
||||
|
||||
//==============================================================================
|
||||
#if JUCE_MAC && JUCE_PPC
|
||||
static void* NewCFMFromMachO (void* const machofp) noexcept
|
||||
{
|
||||
void* result = (void*) new char[8];
|
||||
|
||||
((void**) result)[0] = machofp;
|
||||
((void**) result)[1] = result;
|
||||
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
//==============================================================================
|
||||
#if JUCE_LINUX
|
||||
|
||||
extern Display* display;
|
||||
extern XContext windowHandleXContext;
|
||||
|
||||
typedef void (*EventProcPtr) (XEvent* ev);
|
||||
|
||||
namespace
|
||||
{
|
||||
static bool xErrorTriggered = false;
|
||||
@@ -254,6 +242,8 @@ namespace
|
||||
return 0;
|
||||
}
|
||||
|
||||
typedef void (*EventProcPtr) (XEvent* ev);
|
||||
|
||||
static EventProcPtr getPropertyFromXWindow (Window handle, Atom atom)
|
||||
{
|
||||
XErrorHandler oldErrorHandler = XSetErrorHandler (temporaryErrorHandler);
|
||||
@@ -269,8 +259,7 @@ namespace
|
||||
|
||||
XSetErrorHandler (oldErrorHandler);
|
||||
|
||||
return (userCount == 1 && ! xErrorTriggered) ? *reinterpret_cast<EventProcPtr*> (data)
|
||||
: 0;
|
||||
return (userCount == 1 && ! xErrorTriggered) ? *reinterpret_cast<EventProcPtr*> (data) : nullptr;
|
||||
}
|
||||
|
||||
Window getChildWindow (Window windowToCheck)
|
||||
@@ -279,12 +268,7 @@ namespace
|
||||
Window* childWindows;
|
||||
unsigned int numChildren = 0;
|
||||
|
||||
XQueryTree (display,
|
||||
windowToCheck,
|
||||
&rootWindow,
|
||||
&parentWindow,
|
||||
&childWindows,
|
||||
&numChildren);
|
||||
XQueryTree (display, windowToCheck, &rootWindow, &parentWindow, &childWindows, &numChildren);
|
||||
|
||||
if (numChildren > 0)
|
||||
return childWindows [0];
|
||||
@@ -354,9 +338,9 @@ public:
|
||||
|
||||
typedef ReferenceCountedObjectPtr<ModuleHandle> Ptr;
|
||||
|
||||
static Array <ModuleHandle*>& getActiveModules()
|
||||
static Array<ModuleHandle*>& getActiveModules()
|
||||
{
|
||||
static Array <ModuleHandle*> activeModules;
|
||||
static Array<ModuleHandle*> activeModules;
|
||||
return activeModules;
|
||||
}
|
||||
|
||||
@@ -470,7 +454,7 @@ public:
|
||||
{
|
||||
if (HGLOBAL hGlob = LoadResource (dllModule, res))
|
||||
{
|
||||
const char* data = static_cast <const char*> (LockResource (hGlob));
|
||||
const char* data = static_cast<const char*> (LockResource (hGlob));
|
||||
return String::fromUTF8 (data, SizeofResource (dllModule, res));
|
||||
}
|
||||
}
|
||||
@@ -552,7 +536,7 @@ public:
|
||||
}
|
||||
}
|
||||
}
|
||||
#if JUCE_PPC
|
||||
#if JUCE_PPC
|
||||
else
|
||||
{
|
||||
FSRef fn;
|
||||
@@ -605,7 +589,7 @@ public:
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
return ok;
|
||||
}
|
||||
@@ -683,7 +667,7 @@ public:
|
||||
|
||||
static void disposeMachOFromCFM (void* ptr)
|
||||
{
|
||||
delete[] static_cast <UInt32*> (ptr);
|
||||
delete[] static_cast<UInt32*> (ptr);
|
||||
}
|
||||
|
||||
void coerceAEffectFunctionCalls (AEffect* eff)
|
||||
@@ -715,11 +699,11 @@ class VSTPluginInstance : public AudioPluginInstance,
|
||||
private AsyncUpdater
|
||||
{
|
||||
public:
|
||||
VSTPluginInstance (const ModuleHandle::Ptr& module_)
|
||||
VSTPluginInstance (const ModuleHandle::Ptr& mh)
|
||||
: effect (nullptr),
|
||||
module (module_),
|
||||
module (mh),
|
||||
usesCocoaNSView (false),
|
||||
name (module_->pluginName),
|
||||
name (mh->pluginName),
|
||||
wantsMidiMessages (false),
|
||||
initialised (false),
|
||||
isPowerOn (false),
|
||||
@@ -741,7 +725,7 @@ public:
|
||||
{
|
||||
static void* audioMasterCoerced = nullptr;
|
||||
if (audioMasterCoerced == nullptr)
|
||||
audioMasterCoerced = NewCFMFromMachO ((void*) &audioMaster);
|
||||
audioMasterCoerced = newCFMFromMachO ((void*) &audioMaster);
|
||||
|
||||
effect = module->moduleMain ((audioMasterCallback) audioMasterCoerced);
|
||||
}
|
||||
@@ -803,7 +787,7 @@ public:
|
||||
char buffer [512] = { 0 };
|
||||
dispatch (effGetEffectName, 0, 0, buffer, 0);
|
||||
|
||||
desc.descriptiveName = String (buffer).trim();
|
||||
desc.descriptiveName = String::fromUTF8 (buffer).trim();
|
||||
|
||||
if (desc.descriptiveName.isEmpty())
|
||||
desc.descriptiveName = name;
|
||||
@@ -818,7 +802,7 @@ public:
|
||||
{
|
||||
char buffer [kVstMaxVendorStrLen + 8] = { 0 };
|
||||
dispatch (effGetVendorString, 0, 0, buffer, 0);
|
||||
desc.manufacturerName = buffer;
|
||||
desc.manufacturerName = String::fromUTF8 (buffer);
|
||||
}
|
||||
|
||||
desc.version = getVersion();
|
||||
@@ -1146,8 +1130,7 @@ public:
|
||||
|
||||
bool isValidChannel (int index, bool isInput) const
|
||||
{
|
||||
return isInput ? (index < getNumInputChannels())
|
||||
: (index < getNumOutputChannels());
|
||||
return isPositiveAndBelow (index, isInput ? getNumInputChannels() : getNumOutputChannels());
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
@@ -1214,7 +1197,7 @@ public:
|
||||
char nm[264] = { 0 };
|
||||
|
||||
if (dispatch (effGetProgramNameIndexed, jlimit (0, getNumPrograms(), index), -1, nm, 0) != 0)
|
||||
return String (CharPointer_UTF8 (nm)).trim();
|
||||
return String::fromUTF8 (nm).trim();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1285,7 +1268,8 @@ public:
|
||||
handleUpdateNowIfNeeded();
|
||||
|
||||
for (int i = ComponentPeer::getNumPeers(); --i >= 0;)
|
||||
ComponentPeer::getPeer(i)->performAnyPendingRepaintsNow();
|
||||
if (ComponentPeer* p = ComponentPeer::getPeer(i))
|
||||
p->performAnyPendingRepaintsNow();
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -1448,20 +1432,20 @@ public:
|
||||
|
||||
const fxSet* const set = (const fxSet*) data;
|
||||
|
||||
if ((vst_swap (set->chunkMagic) != 'CcnK' && vst_swap (set->chunkMagic) != 'KncC')
|
||||
|| vst_swap (set->version) > fxbVersionNum)
|
||||
if ((set->chunkMagic != fxbName ("CcnK") && set->chunkMagic != fxbName ("KncC"))
|
||||
|| fxbSwap (set->version) > fxbVersionNum)
|
||||
return false;
|
||||
|
||||
if (vst_swap (set->fxMagic) == 'FxBk')
|
||||
if (set->fxMagic == fxbName ("FxBk"))
|
||||
{
|
||||
// bank of programs
|
||||
if (vst_swap (set->numPrograms) >= 0)
|
||||
if (fxbSwap (set->numPrograms) >= 0)
|
||||
{
|
||||
const int oldProg = getCurrentProgram();
|
||||
const int numParams = vst_swap (((const fxProgram*) (set->programs))->numParams);
|
||||
const int numParams = fxbSwap (((const fxProgram*) (set->programs))->numParams);
|
||||
const int progLen = sizeof (fxProgram) + (numParams - 1) * sizeof (float);
|
||||
|
||||
for (int i = 0; i < vst_swap (set->numPrograms); ++i)
|
||||
for (int i = 0; i < fxbSwap (set->numPrograms); ++i)
|
||||
{
|
||||
if (i != oldProg)
|
||||
{
|
||||
@@ -1469,7 +1453,7 @@ public:
|
||||
if (((const char*) prog) - ((const char*) set) >= (ssize_t) dataSize)
|
||||
return false;
|
||||
|
||||
if (vst_swap (set->numPrograms) > 0)
|
||||
if (fxbSwap (set->numPrograms) > 0)
|
||||
setCurrentProgram (i);
|
||||
|
||||
if (! restoreProgramSettings (prog))
|
||||
@@ -1477,7 +1461,7 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
if (vst_swap (set->numPrograms) > 0)
|
||||
if (fxbSwap (set->numPrograms) > 0)
|
||||
setCurrentProgram (oldProg);
|
||||
|
||||
const fxProgram* const prog = (const fxProgram*) (((const char*) (set->programs)) + oldProg * progLen);
|
||||
@@ -1488,38 +1472,38 @@ public:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (vst_swap (set->fxMagic) == 'FxCk')
|
||||
else if (set->fxMagic == fxbName ("FxCk"))
|
||||
{
|
||||
// single program
|
||||
const fxProgram* const prog = (const fxProgram*) data;
|
||||
|
||||
if (vst_swap (prog->chunkMagic) != 'CcnK')
|
||||
if (prog->chunkMagic != fxbName ("CcnK"))
|
||||
return false;
|
||||
|
||||
changeProgramName (getCurrentProgram(), prog->prgName);
|
||||
|
||||
for (int i = 0; i < vst_swap (prog->numParams); ++i)
|
||||
setParameter (i, vst_swapFloat (prog->params[i]));
|
||||
for (int i = 0; i < fxbSwap (prog->numParams); ++i)
|
||||
setParameter (i, fxbSwapFloat (prog->params[i]));
|
||||
}
|
||||
else if (vst_swap (set->fxMagic) == 'FBCh' || vst_swap (set->fxMagic) == 'hCBF')
|
||||
else if (set->fxMagic == fxbName ("FBCh") || set->fxMagic == fxbName ("hCBF"))
|
||||
{
|
||||
// non-preset chunk
|
||||
const fxChunkSet* const cset = (const fxChunkSet*) data;
|
||||
|
||||
if (vst_swap (cset->chunkSize) + sizeof (fxChunkSet) - 8 > (unsigned int) dataSize)
|
||||
if (fxbSwap (cset->chunkSize) + sizeof (fxChunkSet) - 8 > (unsigned int) dataSize)
|
||||
return false;
|
||||
|
||||
setChunkData (cset->chunk, vst_swap (cset->chunkSize), false);
|
||||
setChunkData (cset->chunk, fxbSwap (cset->chunkSize), false);
|
||||
}
|
||||
else if (vst_swap (set->fxMagic) == 'FPCh' || vst_swap (set->fxMagic) == 'hCPF')
|
||||
else if (set->fxMagic == fxbName ("FPCh") || set->fxMagic == fxbName ("hCPF"))
|
||||
{
|
||||
// preset chunk
|
||||
const fxProgramSet* const cset = (const fxProgramSet*) data;
|
||||
|
||||
if (vst_swap (cset->chunkSize) + sizeof (fxProgramSet) - 8 > (unsigned int) dataSize)
|
||||
if (fxbSwap (cset->chunkSize) + sizeof (fxProgramSet) - 8 > (unsigned int) dataSize)
|
||||
return false;
|
||||
|
||||
setChunkData (cset->chunk, vst_swap (cset->chunkSize), true);
|
||||
setChunkData (cset->chunk, fxbSwap (cset->chunkSize), true);
|
||||
|
||||
changeProgramName (getCurrentProgram(), cset->name);
|
||||
}
|
||||
@@ -1547,14 +1531,14 @@ public:
|
||||
dest.setSize (totalLen, true);
|
||||
|
||||
fxChunkSet* const set = (fxChunkSet*) dest.getData();
|
||||
set->chunkMagic = vst_swap ('CcnK');
|
||||
set->chunkMagic = fxbName ("CcnK");
|
||||
set->byteSize = 0;
|
||||
set->fxMagic = vst_swap ('FBCh');
|
||||
set->version = vst_swap (fxbVersionNum);
|
||||
set->fxID = vst_swap (getUID());
|
||||
set->fxVersion = vst_swap (getVersionNumber());
|
||||
set->numPrograms = vst_swap (numPrograms);
|
||||
set->chunkSize = vst_swap ((VstInt32) chunk.getSize());
|
||||
set->fxMagic = fxbName ("FBCh");
|
||||
set->version = fxbSwap (fxbVersionNum);
|
||||
set->fxID = fxbSwap (getUID());
|
||||
set->fxVersion = fxbSwap (getVersionNumber());
|
||||
set->numPrograms = fxbSwap (numPrograms);
|
||||
set->chunkSize = fxbSwap ((VstInt32) chunk.getSize());
|
||||
|
||||
chunk.copyTo (set->chunk, 0, chunk.getSize());
|
||||
}
|
||||
@@ -1564,14 +1548,14 @@ public:
|
||||
dest.setSize (totalLen, true);
|
||||
|
||||
fxProgramSet* const set = (fxProgramSet*) dest.getData();
|
||||
set->chunkMagic = vst_swap ('CcnK');
|
||||
set->chunkMagic = fxbName ("CcnK");
|
||||
set->byteSize = 0;
|
||||
set->fxMagic = vst_swap ('FPCh');
|
||||
set->version = vst_swap (fxbVersionNum);
|
||||
set->fxID = vst_swap (getUID());
|
||||
set->fxVersion = vst_swap (getVersionNumber());
|
||||
set->numPrograms = vst_swap (numPrograms);
|
||||
set->chunkSize = vst_swap ((VstInt32) chunk.getSize());
|
||||
set->fxMagic = fxbName ("FPCh");
|
||||
set->version = fxbSwap (fxbVersionNum);
|
||||
set->fxID = fxbSwap (getUID());
|
||||
set->fxVersion = fxbSwap (getVersionNumber());
|
||||
set->numPrograms = fxbSwap (numPrograms);
|
||||
set->chunkSize = fxbSwap ((VstInt32) chunk.getSize());
|
||||
|
||||
getCurrentProgramName().copyToUTF8 (set->name, sizeof (set->name) - 1);
|
||||
chunk.copyTo (set->chunk, 0, chunk.getSize());
|
||||
@@ -1586,13 +1570,13 @@ public:
|
||||
dest.setSize (len, true);
|
||||
|
||||
fxSet* const set = (fxSet*) dest.getData();
|
||||
set->chunkMagic = vst_swap ('CcnK');
|
||||
set->chunkMagic = fxbName ("CcnK");
|
||||
set->byteSize = 0;
|
||||
set->fxMagic = vst_swap ('FxBk');
|
||||
set->version = vst_swap (fxbVersionNum);
|
||||
set->fxID = vst_swap (getUID());
|
||||
set->fxVersion = vst_swap (getVersionNumber());
|
||||
set->numPrograms = vst_swap (numPrograms);
|
||||
set->fxMagic = fxbName ("FxBk");
|
||||
set->version = fxbSwap (fxbVersionNum);
|
||||
set->fxID = fxbSwap (getUID());
|
||||
set->fxVersion = fxbSwap (getVersionNumber());
|
||||
set->numPrograms = fxbSwap (numPrograms);
|
||||
|
||||
const int oldProgram = getCurrentProgram();
|
||||
MemoryBlock oldSettings;
|
||||
@@ -1687,12 +1671,12 @@ private:
|
||||
|
||||
bool restoreProgramSettings (const fxProgram* const prog)
|
||||
{
|
||||
if (vst_swap (prog->chunkMagic) == 'CcnK' && vst_swap (prog->fxMagic) == 'FxCk')
|
||||
if (prog->chunkMagic == fxbName ("CcnK") && prog->fxMagic == fxbName ("FxCk"))
|
||||
{
|
||||
changeProgramName (getCurrentProgram(), prog->prgName);
|
||||
|
||||
for (int i = 0; i < vst_swap (prog->numParams); ++i)
|
||||
setParameter (i, vst_swapFloat (prog->params[i]));
|
||||
for (int i = 0; i < fxbSwap (prog->numParams); ++i)
|
||||
setParameter (i, fxbSwapFloat (prog->params[i]));
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -1741,18 +1725,18 @@ private:
|
||||
{
|
||||
const int numParams = getNumParameters();
|
||||
|
||||
prog->chunkMagic = vst_swap ('CcnK');
|
||||
prog->chunkMagic = fxbName ("CcnK");
|
||||
prog->byteSize = 0;
|
||||
prog->fxMagic = vst_swap ('FxCk');
|
||||
prog->version = vst_swap (fxbVersionNum);
|
||||
prog->fxID = vst_swap (getUID());
|
||||
prog->fxVersion = vst_swap (getVersionNumber());
|
||||
prog->numParams = vst_swap (numParams);
|
||||
prog->fxMagic = fxbName ("FxCk");
|
||||
prog->version = fxbSwap (fxbVersionNum);
|
||||
prog->fxID = fxbSwap (getUID());
|
||||
prog->fxVersion = fxbSwap (getVersionNumber());
|
||||
prog->numParams = fxbSwap (numParams);
|
||||
|
||||
getCurrentProgramName().copyToUTF8 (prog->prgName, sizeof (prog->prgName) - 1);
|
||||
|
||||
for (int i = 0; i < numParams; ++i)
|
||||
prog->params[i] = vst_swapFloat (getParameter (i));
|
||||
prog->params[i] = fxbSwapFloat (getParameter (i));
|
||||
}
|
||||
|
||||
void updateStoredProgramNames()
|
||||
@@ -1894,7 +1878,8 @@ private:
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
static Array <VSTPluginWindow*> activeVSTWindows;
|
||||
class VSTPluginWindow;
|
||||
static Array<VSTPluginWindow*> activeVSTWindows;
|
||||
|
||||
//==============================================================================
|
||||
class VSTPluginWindow : public AudioProcessorEditor,
|
||||
@@ -2232,10 +2217,11 @@ private:
|
||||
#pragma warning (push)
|
||||
#pragma warning (disable: 4244)
|
||||
|
||||
originalWndProc = (void*) GetWindowLongPtr (pluginHWND, GWLP_WNDPROC);
|
||||
|
||||
if (! pluginWantsKeys)
|
||||
{
|
||||
originalWndProc = (void*) GetWindowLongPtr (pluginHWND, GWLP_WNDPROC);
|
||||
SetWindowLongPtr (pluginHWND, GWLP_WNDPROC, (LONG_PTR) vstHookWndProc);
|
||||
}
|
||||
|
||||
#pragma warning (pop)
|
||||
|
||||
@@ -2317,26 +2303,24 @@ private:
|
||||
{
|
||||
if (isOpen)
|
||||
{
|
||||
#if ! (JUCE_MAC && JUCE_SUPPORT_CARBON)
|
||||
JUCE_VST_LOG ("Closing VST UI: " + plugin.getName());
|
||||
isOpen = false;
|
||||
|
||||
dispatch (effEditClose, 0, 0, 0, 0);
|
||||
stopTimer();
|
||||
|
||||
#if JUCE_WINDOWS
|
||||
#pragma warning (push)
|
||||
#pragma warning (disable: 4244)
|
||||
if (pluginHWND != 0 && IsWindow (pluginHWND))
|
||||
if (originalWndProc != 0 && pluginHWND != 0 && IsWindow (pluginHWND))
|
||||
SetWindowLongPtr (pluginHWND, GWLP_WNDPROC, (LONG_PTR) originalWndProc);
|
||||
#pragma warning (pop)
|
||||
|
||||
originalWndProc = 0;
|
||||
pluginHWND = 0;
|
||||
#elif JUCE_LINUX
|
||||
pluginWindow = 0;
|
||||
pluginProc = 0;
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2845,7 +2829,7 @@ FileSearchPath VSTPluginFormat::getDefaultLocationsToSearch()
|
||||
|
||||
const XmlElement* VSTPluginFormat::getVSTXML (AudioPluginInstance* plugin)
|
||||
{
|
||||
if (VSTPluginInstance* const vst = dynamic_cast <VSTPluginInstance*> (plugin))
|
||||
if (VSTPluginInstance* const vst = dynamic_cast<VSTPluginInstance*> (plugin))
|
||||
if (vst->module != nullptr)
|
||||
return vst->module->vstXml.get();
|
||||
|
||||
@@ -2854,7 +2838,7 @@ const XmlElement* VSTPluginFormat::getVSTXML (AudioPluginInstance* plugin)
|
||||
|
||||
bool VSTPluginFormat::loadFromFXBFile (AudioPluginInstance* plugin, const void* data, size_t dataSize)
|
||||
{
|
||||
if (VSTPluginInstance* vst = dynamic_cast <VSTPluginInstance*> (plugin))
|
||||
if (VSTPluginInstance* vst = dynamic_cast<VSTPluginInstance*> (plugin))
|
||||
return vst->loadFromFXBFile (data, dataSize);
|
||||
|
||||
return false;
|
||||
@@ -2862,7 +2846,7 @@ bool VSTPluginFormat::loadFromFXBFile (AudioPluginInstance* plugin, const void*
|
||||
|
||||
bool VSTPluginFormat::saveToFXBFile (AudioPluginInstance* plugin, MemoryBlock& dest, bool asFXB)
|
||||
{
|
||||
if (VSTPluginInstance* vst = dynamic_cast <VSTPluginInstance*> (plugin))
|
||||
if (VSTPluginInstance* vst = dynamic_cast<VSTPluginInstance*> (plugin))
|
||||
return vst->saveToFXBFile (dest, asFXB);
|
||||
|
||||
return false;
|
||||
@@ -2870,7 +2854,7 @@ bool VSTPluginFormat::saveToFXBFile (AudioPluginInstance* plugin, MemoryBlock& d
|
||||
|
||||
bool VSTPluginFormat::getChunkData (AudioPluginInstance* plugin, MemoryBlock& result, bool isPreset)
|
||||
{
|
||||
if (VSTPluginInstance* vst = dynamic_cast <VSTPluginInstance*> (plugin))
|
||||
if (VSTPluginInstance* vst = dynamic_cast<VSTPluginInstance*> (plugin))
|
||||
return vst->getChunkData (result, isPreset, 128);
|
||||
|
||||
return false;
|
||||
@@ -2878,7 +2862,7 @@ bool VSTPluginFormat::getChunkData (AudioPluginInstance* plugin, MemoryBlock& re
|
||||
|
||||
bool VSTPluginFormat::setChunkData (AudioPluginInstance* plugin, const void* data, int size, bool isPreset)
|
||||
{
|
||||
if (VSTPluginInstance* vst = dynamic_cast <VSTPluginInstance*> (plugin))
|
||||
if (VSTPluginInstance* vst = dynamic_cast<VSTPluginInstance*> (plugin))
|
||||
return vst->setChunkData (data, size, isPreset);
|
||||
|
||||
return false;
|
||||
@@ -2888,13 +2872,13 @@ void VSTPluginFormat::setExtraFunctions (AudioPluginInstance* plugin, ExtraFunct
|
||||
{
|
||||
ScopedPointer<ExtraFunctions> f (functions);
|
||||
|
||||
if (VSTPluginInstance* vst = dynamic_cast <VSTPluginInstance*> (plugin))
|
||||
if (VSTPluginInstance* vst = dynamic_cast<VSTPluginInstance*> (plugin))
|
||||
vst->extraFunctions = f;
|
||||
}
|
||||
|
||||
VSTPluginFormat::VstIntPtr JUCE_CALLTYPE VSTPluginFormat::dispatcher (AudioPluginInstance* plugin, int32 opcode, int32 index, VstIntPtr value, void* ptr, float opt)
|
||||
{
|
||||
if (VSTPluginInstance* vst = dynamic_cast <VSTPluginInstance*> (plugin))
|
||||
if (VSTPluginInstance* vst = dynamic_cast<VSTPluginInstance*> (plugin))
|
||||
return vst->dispatch (opcode, index, value, ptr, opt);
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -41,8 +41,9 @@
|
||||
|
||||
//==============================================================================
|
||||
#if JUCE_MAC
|
||||
#if (JUCE_PLUGINHOST_VST || JUCE_PLUGINHOST_AU) \
|
||||
|| ! (defined (MAC_OS_X_VERSION_10_6) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_6)
|
||||
#if JUCE_SUPPORT_CARBON \
|
||||
&& ((JUCE_PLUGINHOST_VST || JUCE_PLUGINHOST_AU) \
|
||||
|| ! (defined (MAC_OS_X_VERSION_10_6) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_6))
|
||||
#define Point CarbonDummyPointName // (workaround to avoid definition of "Point" by old Carbon headers)
|
||||
#define Component CarbonDummyCompName
|
||||
#include <Carbon/Carbon.h>
|
||||
@@ -112,27 +113,24 @@ struct AutoResizingNSViewComponentWithParent : public AutoResizingNSViewCompone
|
||||
setView (v);
|
||||
[v release];
|
||||
|
||||
startTimer (100);
|
||||
startTimer (30);
|
||||
}
|
||||
|
||||
NSView* getChildView() const
|
||||
{
|
||||
if (NSView* parent = (NSView*) getView())
|
||||
if ([[parent subviews] count] > 0)
|
||||
return [[parent subviews] objectAtIndex: 0];
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
void timerCallback() override
|
||||
{
|
||||
if (NSView* parent = (NSView*) getView())
|
||||
if (NSView* child = getChildView())
|
||||
{
|
||||
if ([[parent subviews] count] > 0)
|
||||
{
|
||||
if (NSView* child = [[parent subviews] objectAtIndex: 0])
|
||||
{
|
||||
NSRect f = [parent frame];
|
||||
NSSize newSize = [child frame].size;
|
||||
|
||||
if (f.size.width != newSize.width || f.size.height != newSize.height)
|
||||
{
|
||||
f.size = newSize;
|
||||
[parent setFrame: f];
|
||||
}
|
||||
}
|
||||
}
|
||||
stopTimer();
|
||||
setView (child);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -76,6 +76,7 @@ class AudioProcessor;
|
||||
#include "processors/juce_AudioPlayHead.h"
|
||||
#include "processors/juce_AudioProcessorEditor.h"
|
||||
#include "processors/juce_AudioProcessorListener.h"
|
||||
#include "processors/juce_AudioProcessorParameter.h"
|
||||
#include "processors/juce_AudioProcessor.h"
|
||||
#include "processors/juce_PluginDescription.h"
|
||||
#include "processors/juce_AudioPluginInstance.h"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"id": "juce_audio_processors",
|
||||
"name": "JUCE audio plugin hosting classes",
|
||||
"version": "3.0.5",
|
||||
"version": "3.0.8",
|
||||
"description": "Classes for loading and playing VST, AU, or internally-generated audio processors.",
|
||||
"website": "http://www.juce.com/juce",
|
||||
"license": "GPL/Commercial",
|
||||
|
||||
@@ -118,19 +118,6 @@ void AudioProcessor::setParameterNotifyingHost (const int parameterIndex,
|
||||
sendParamChangeMessageToListeners (parameterIndex, newValue);
|
||||
}
|
||||
|
||||
String AudioProcessor::getParameterName (int parameterIndex, int maximumStringLength)
|
||||
{
|
||||
return getParameterName (parameterIndex).substring (0, maximumStringLength);
|
||||
}
|
||||
|
||||
String AudioProcessor::getParameterText (int parameterIndex, int maximumStringLength)
|
||||
{
|
||||
return getParameterText (parameterIndex).substring (0, maximumStringLength);
|
||||
}
|
||||
|
||||
int AudioProcessor::getParameterNumSteps (int /*parameterIndex*/) { return 0x7fffffff; }
|
||||
float AudioProcessor::getParameterDefaultValue (int /*parameterIndex*/) { return 0.0f; }
|
||||
|
||||
AudioProcessorListener* AudioProcessor::getListenerLocked (const int index) const noexcept
|
||||
{
|
||||
const ScopedLock sl (listenerLock);
|
||||
@@ -201,9 +188,129 @@ void AudioProcessor::updateHostDisplay()
|
||||
l->audioProcessorChanged (this);
|
||||
}
|
||||
|
||||
String AudioProcessor::getParameterLabel (int) const { return String(); }
|
||||
bool AudioProcessor::isParameterAutomatable (int) const { return true; }
|
||||
bool AudioProcessor::isMetaParameter (int) const { return false; }
|
||||
const OwnedArray<AudioProcessorParameter>& AudioProcessor::getParameters() const noexcept
|
||||
{
|
||||
return managedParameters;
|
||||
}
|
||||
|
||||
int AudioProcessor::getNumParameters()
|
||||
{
|
||||
return managedParameters.size();
|
||||
}
|
||||
|
||||
float AudioProcessor::getParameter (int index)
|
||||
{
|
||||
if (AudioProcessorParameter* p = getParamChecked (index))
|
||||
return p->getValue();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void AudioProcessor::setParameter (int index, float newValue)
|
||||
{
|
||||
if (AudioProcessorParameter* p = getParamChecked (index))
|
||||
p->setValue (newValue);
|
||||
}
|
||||
|
||||
float AudioProcessor::getParameterDefaultValue (int index)
|
||||
{
|
||||
if (AudioProcessorParameter* p = managedParameters[index])
|
||||
return p->getDefaultValue();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const String AudioProcessor::getParameterName (int index)
|
||||
{
|
||||
if (AudioProcessorParameter* p = getParamChecked (index))
|
||||
return p->getName (512);
|
||||
|
||||
return String();
|
||||
}
|
||||
|
||||
String AudioProcessor::getParameterName (int index, int maximumStringLength)
|
||||
{
|
||||
if (AudioProcessorParameter* p = managedParameters[index])
|
||||
return p->getName (maximumStringLength);
|
||||
|
||||
return getParameterName (index).substring (0, maximumStringLength);
|
||||
}
|
||||
|
||||
const String AudioProcessor::getParameterText (int index)
|
||||
{
|
||||
return getParameterText (index, 1024);
|
||||
}
|
||||
|
||||
String AudioProcessor::getParameterText (int index, int maximumStringLength)
|
||||
{
|
||||
if (AudioProcessorParameter* p = managedParameters[index])
|
||||
return p->getText (p->getValue(), maximumStringLength);
|
||||
|
||||
return getParameterText (index).substring (0, maximumStringLength);
|
||||
}
|
||||
|
||||
int AudioProcessor::getParameterNumSteps (int index)
|
||||
{
|
||||
if (AudioProcessorParameter* p = managedParameters[index])
|
||||
return p->getNumSteps();
|
||||
|
||||
return AudioProcessor::getDefaultNumParameterSteps();
|
||||
}
|
||||
|
||||
int AudioProcessor::getDefaultNumParameterSteps() noexcept
|
||||
{
|
||||
return 0x7fffffff;
|
||||
}
|
||||
|
||||
String AudioProcessor::getParameterLabel (int index) const
|
||||
{
|
||||
if (AudioProcessorParameter* p = managedParameters[index])
|
||||
return p->getLabel();
|
||||
|
||||
return String();
|
||||
}
|
||||
|
||||
bool AudioProcessor::isParameterAutomatable (int index) const
|
||||
{
|
||||
if (AudioProcessorParameter* p = managedParameters[index])
|
||||
return p->isAutomatable();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AudioProcessor::isParameterOrientationInverted (int index) const
|
||||
{
|
||||
if (AudioProcessorParameter* p = managedParameters[index])
|
||||
return p->isOrientationInverted();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AudioProcessor::isMetaParameter (int index) const
|
||||
{
|
||||
if (AudioProcessorParameter* p = managedParameters[index])
|
||||
return p->isMetaParameter();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
AudioProcessorParameter* AudioProcessor::getParamChecked (int index) const noexcept
|
||||
{
|
||||
AudioProcessorParameter* p = managedParameters[index];
|
||||
|
||||
// If you hit this, then you're either trying to access parameters that are out-of-range,
|
||||
// or you're not using addParameter and the managed parameter list, but have failed
|
||||
// to override some essential virtual methods and implement them appropriately.
|
||||
jassert (p != nullptr);
|
||||
return p;
|
||||
}
|
||||
|
||||
void AudioProcessor::addParameter (AudioProcessorParameter* p)
|
||||
{
|
||||
p->processor = this;
|
||||
p->parameterIndex = managedParameters.size();
|
||||
managedParameters.add (p);
|
||||
}
|
||||
|
||||
void AudioProcessor::suspendProcessing (const bool shouldBeSuspended)
|
||||
{
|
||||
@@ -230,9 +337,6 @@ AudioProcessorEditor* AudioProcessor::createEditorIfNeeded()
|
||||
|
||||
AudioProcessorEditor* const ed = createEditor();
|
||||
|
||||
// You must make your hasEditor() method return a consistent result!
|
||||
jassert (hasEditor() == (ed != nullptr));
|
||||
|
||||
if (ed != nullptr)
|
||||
{
|
||||
// you must give your editor comp a size before returning it..
|
||||
@@ -242,6 +346,9 @@ AudioProcessorEditor* AudioProcessor::createEditorIfNeeded()
|
||||
activeEditor = ed;
|
||||
}
|
||||
|
||||
// You must make your hasEditor() method return a consistent result!
|
||||
jassert (hasEditor() == (ed != nullptr));
|
||||
|
||||
return ed;
|
||||
}
|
||||
|
||||
@@ -294,6 +401,47 @@ XmlElement* AudioProcessor::getXmlFromBinary (const void* data, const int sizeIn
|
||||
void AudioProcessorListener::audioProcessorParameterChangeGestureBegin (AudioProcessor*, int) {}
|
||||
void AudioProcessorListener::audioProcessorParameterChangeGestureEnd (AudioProcessor*, int) {}
|
||||
|
||||
//==============================================================================
|
||||
AudioProcessorParameter::AudioProcessorParameter() noexcept
|
||||
: processor (nullptr), parameterIndex (-1)
|
||||
{}
|
||||
|
||||
AudioProcessorParameter::~AudioProcessorParameter() {}
|
||||
|
||||
void AudioProcessorParameter::setValueNotifyingHost (float newValue)
|
||||
{
|
||||
// This method can't be used until the parameter has been attached to a processor!
|
||||
jassert (processor != nullptr && parameterIndex >= 0);
|
||||
|
||||
return processor->setParameterNotifyingHost (parameterIndex, newValue);
|
||||
}
|
||||
|
||||
void AudioProcessorParameter::beginChangeGesture()
|
||||
{
|
||||
// This method can't be used until the parameter has been attached to a processor!
|
||||
jassert (processor != nullptr && parameterIndex >= 0);
|
||||
|
||||
processor->beginParameterChangeGesture (parameterIndex);
|
||||
}
|
||||
|
||||
void AudioProcessorParameter::endChangeGesture()
|
||||
{
|
||||
// This method can't be used until the parameter has been attached to a processor!
|
||||
jassert (processor != nullptr && parameterIndex >= 0);
|
||||
|
||||
processor->endParameterChangeGesture (parameterIndex);
|
||||
}
|
||||
|
||||
bool AudioProcessorParameter::isOrientationInverted() const { return false; }
|
||||
bool AudioProcessorParameter::isAutomatable() const { return true; }
|
||||
bool AudioProcessorParameter::isMetaParameter() const { return false; }
|
||||
int AudioProcessorParameter::getNumSteps() const { return AudioProcessor::getDefaultNumParameterSteps(); }
|
||||
|
||||
String AudioProcessorParameter::getText (float value, int /*maximumStringLength*/) const
|
||||
{
|
||||
return String (value, 2);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
bool AudioPlayHead::CurrentPositionInfo::operator== (const CurrentPositionInfo& other) const noexcept
|
||||
{
|
||||
|
||||
@@ -44,11 +44,7 @@ class JUCE_API AudioProcessor
|
||||
{
|
||||
protected:
|
||||
//==============================================================================
|
||||
/** Constructor.
|
||||
|
||||
You can also do your initialisation tasks in the initialiseFilterInfo()
|
||||
call, which will be made after this object has been created.
|
||||
*/
|
||||
/** Constructor. */
|
||||
AudioProcessor();
|
||||
|
||||
public:
|
||||
@@ -293,9 +289,9 @@ public:
|
||||
filter will return an empty buffer, but won't block the audio thread like it would
|
||||
do if you use the getCallbackLock() critical section to synchronise access.
|
||||
|
||||
If you're going to use this, your processBlock() method must call isSuspended() and
|
||||
check whether it's suspended or not. If it is, then it should skip doing any real
|
||||
processing, either emitting silence or passing the input through unchanged.
|
||||
Any code that calls processBlock() should call isSuspended() before doing so, and
|
||||
if the processor is suspended, it should avoid the call and emit silence or
|
||||
whatever is appropriate.
|
||||
|
||||
@see getCallbackLock
|
||||
*/
|
||||
@@ -329,7 +325,7 @@ public:
|
||||
/** Called by the host to tell this processor whether it's being used in a non-realtime
|
||||
capacity for offline rendering or bouncing.
|
||||
*/
|
||||
void setNonRealtime (bool isNonRealtime) noexcept;
|
||||
virtual void setNonRealtime (bool isNonRealtime) noexcept;
|
||||
|
||||
//==============================================================================
|
||||
/** Creates the filter's UI.
|
||||
@@ -381,10 +377,10 @@ public:
|
||||
/** This must return the correct value immediately after the object has been
|
||||
created, and mustn't change the number of parameters later.
|
||||
*/
|
||||
virtual int getNumParameters() = 0;
|
||||
virtual int getNumParameters();
|
||||
|
||||
/** Returns the name of a particular parameter. */
|
||||
virtual const String getParameterName (int parameterIndex) = 0;
|
||||
virtual const String getParameterName (int parameterIndex);
|
||||
|
||||
/** Called by the host to find out the value of one of the filter's parameters.
|
||||
|
||||
@@ -394,10 +390,10 @@ public:
|
||||
It's also likely to be called by non-UI threads, so the code in here should
|
||||
be thread-aware.
|
||||
*/
|
||||
virtual float getParameter (int parameterIndex) = 0;
|
||||
virtual float getParameter (int parameterIndex);
|
||||
|
||||
/** Returns the value of a parameter as a text string. */
|
||||
virtual const String getParameterText (int parameterIndex) = 0;
|
||||
virtual const String getParameterText (int parameterIndex);
|
||||
|
||||
/** Returns the name of a parameter as a text string with a preferred maximum length.
|
||||
If you want to provide customised short versions of your parameter names that
|
||||
@@ -418,12 +414,18 @@ public:
|
||||
virtual String getParameterText (int parameterIndex, int maximumStringLength);
|
||||
|
||||
/** Returns the number of discrete steps that this parameter can represent.
|
||||
The default return value if you don't implement this method is 0x7fffffff.
|
||||
The default return value if you don't implement this method is
|
||||
AudioProcessor::getDefaultNumParameterSteps().
|
||||
If your parameter is boolean, then you may want to make this return 2.
|
||||
The value that is returned may or may not be used, depending on the host.
|
||||
*/
|
||||
virtual int getParameterNumSteps (int parameterIndex);
|
||||
|
||||
/** Returns the default number of steps for a parameter.
|
||||
@see getParameterNumSteps
|
||||
*/
|
||||
static int getDefaultNumParameterSteps() noexcept;
|
||||
|
||||
/** Returns the default value for the parameter.
|
||||
By default, this just returns 0.
|
||||
The value that is returned may or may not be used, depending on the host.
|
||||
@@ -435,6 +437,11 @@ public:
|
||||
*/
|
||||
virtual String getParameterLabel (int index) const;
|
||||
|
||||
/** This can be overridden to tell the host that particular parameters operate in the
|
||||
reverse direction. (Not all plugin formats or hosts will actually use this information).
|
||||
*/
|
||||
virtual bool isParameterOrientationInverted (int index) const;
|
||||
|
||||
/** The host will call this method to change the value of one of the filter's parameters.
|
||||
|
||||
The host may call this at any time, including during the audio processing
|
||||
@@ -448,7 +455,7 @@ public:
|
||||
|
||||
The value passed will be between 0 and 1.0.
|
||||
*/
|
||||
virtual void setParameter (int parameterIndex, float newValue) = 0;
|
||||
virtual void setParameter (int parameterIndex, float newValue);
|
||||
|
||||
/** Your filter can call this when it needs to change one of its parameters.
|
||||
|
||||
@@ -463,16 +470,13 @@ public:
|
||||
void setParameterNotifyingHost (int parameterIndex, float newValue);
|
||||
|
||||
/** Returns true if the host can automate this parameter.
|
||||
|
||||
By default, this returns true for all parameters.
|
||||
*/
|
||||
virtual bool isParameterAutomatable (int parameterIndex) const;
|
||||
|
||||
/** Should return true if this parameter is a "meta" parameter.
|
||||
|
||||
A meta-parameter is a parameter that changes other params. It is used
|
||||
by some hosts (e.g. AudioUnit hosts).
|
||||
|
||||
By default this returns false.
|
||||
*/
|
||||
virtual bool isMetaParameter (int parameterIndex) const;
|
||||
@@ -503,6 +507,16 @@ public:
|
||||
*/
|
||||
void updateHostDisplay();
|
||||
|
||||
//==============================================================================
|
||||
/** Adds a parameter to the list.
|
||||
The parameter object will be managed and deleted automatically by the list
|
||||
when no longer needed.
|
||||
*/
|
||||
void addParameter (AudioProcessorParameter*);
|
||||
|
||||
/** Returns the current list of parameters. */
|
||||
const OwnedArray<AudioProcessorParameter>& getParameters() const noexcept;
|
||||
|
||||
//==============================================================================
|
||||
/** Returns the number of preset programs the filter supports.
|
||||
|
||||
@@ -659,6 +673,9 @@ private:
|
||||
CriticalSection callbackLock, listenerLock;
|
||||
String inputSpeakerArrangement, outputSpeakerArrangement;
|
||||
|
||||
OwnedArray<AudioProcessorParameter> managedParameters;
|
||||
AudioProcessorParameter* getParamChecked (int) const noexcept;
|
||||
|
||||
#if JUCE_DEBUG
|
||||
BigInteger changingParams;
|
||||
#endif
|
||||
|
||||
+10
-4
@@ -22,16 +22,22 @@
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
AudioProcessorEditor::AudioProcessorEditor (AudioProcessor* const p)
|
||||
: owner (p)
|
||||
AudioProcessorEditor::AudioProcessorEditor (AudioProcessor& p) noexcept : processor (p)
|
||||
{
|
||||
}
|
||||
|
||||
AudioProcessorEditor::AudioProcessorEditor (AudioProcessor* p) noexcept : processor (*p)
|
||||
{
|
||||
// the filter must be valid..
|
||||
jassert (owner != nullptr);
|
||||
jassert (p != nullptr);
|
||||
}
|
||||
|
||||
AudioProcessorEditor::~AudioProcessorEditor()
|
||||
{
|
||||
// if this fails, then the wrapper hasn't called editorBeingDeleted() on the
|
||||
// filter for some reason..
|
||||
jassert (owner->getActiveEditor() != this);
|
||||
jassert (processor.getActiveEditor() != this);
|
||||
}
|
||||
|
||||
void AudioProcessorEditor::setControlHighlight (ParameterControlHighlightInfo) {}
|
||||
int AudioProcessorEditor::getControlParameterIndex (Component&) { return -1; }
|
||||
|
||||
+36
-8
@@ -39,9 +39,11 @@ class JUCE_API AudioProcessorEditor : public Component
|
||||
{
|
||||
protected:
|
||||
//==============================================================================
|
||||
/** Creates an editor for the specified processor.
|
||||
*/
|
||||
AudioProcessorEditor (AudioProcessor* owner);
|
||||
/** Creates an editor for the specified processor. */
|
||||
AudioProcessorEditor (AudioProcessor&) noexcept;
|
||||
|
||||
/** Creates an editor for the specified processor. */
|
||||
AudioProcessorEditor (AudioProcessor*) noexcept;
|
||||
|
||||
public:
|
||||
/** Destructor. */
|
||||
@@ -49,14 +51,40 @@ public:
|
||||
|
||||
|
||||
//==============================================================================
|
||||
/** Returns a pointer to the processor that this editor represents. */
|
||||
AudioProcessor* getAudioProcessor() const noexcept { return owner; }
|
||||
/** The AudioProcessor that this editor represents. */
|
||||
AudioProcessor& processor;
|
||||
|
||||
/** Returns a pointer to the processor that this editor represents.
|
||||
This method is here to support legacy code, but it's easier to just use the
|
||||
AudioProcessorEditor::processor member variable directly to get this object.
|
||||
*/
|
||||
AudioProcessor* getAudioProcessor() const noexcept { return &processor; }
|
||||
|
||||
//==============================================================================
|
||||
/** Used by the setParameterHighlighting() method. */
|
||||
struct ParameterControlHighlightInfo
|
||||
{
|
||||
int parameterIndex;
|
||||
bool isHighlighted;
|
||||
Colour suggestedColour;
|
||||
};
|
||||
|
||||
/** Some types of plugin can call this to suggest that the control for a particular
|
||||
parameter should be highlighted.
|
||||
Currently only AAX plugins will call this, and implementing it is optional.
|
||||
*/
|
||||
virtual void setControlHighlight (ParameterControlHighlightInfo);
|
||||
|
||||
/** Called by certain plug-in wrappers to find out whether a component is used
|
||||
to control a parameter.
|
||||
|
||||
If the given component represents a particular plugin parameter, then this
|
||||
method should return the index of that parameter. If not, it should return -1.
|
||||
Currently only AAX plugins will call this, and implementing it is optional.
|
||||
*/
|
||||
virtual int getControlParameterIndex (Component&);
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
AudioProcessor* const owner;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE (AudioProcessorEditor)
|
||||
};
|
||||
|
||||
|
||||
@@ -388,11 +388,11 @@ public:
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
ReferenceCountedArray <Node> nodes;
|
||||
OwnedArray <Connection> connections;
|
||||
ReferenceCountedArray<Node> nodes;
|
||||
OwnedArray<Connection> connections;
|
||||
uint32 lastNodeId;
|
||||
AudioSampleBuffer renderingBuffers;
|
||||
OwnedArray <MidiBuffer> midiBuffers;
|
||||
OwnedArray<MidiBuffer> midiBuffers;
|
||||
Array<void*> renderingOps;
|
||||
|
||||
friend class AudioGraphIOProcessor;
|
||||
|
||||
+26
-15
@@ -27,12 +27,12 @@ class ProcessorParameterPropertyComp : public PropertyComponent,
|
||||
private Timer
|
||||
{
|
||||
public:
|
||||
ProcessorParameterPropertyComp (const String& name, AudioProcessor& p, const int index_)
|
||||
ProcessorParameterPropertyComp (const String& name, AudioProcessor& p, int paramIndex)
|
||||
: PropertyComponent (name),
|
||||
owner (p),
|
||||
index (index_),
|
||||
index (paramIndex),
|
||||
paramHasChanged (false),
|
||||
slider (p, index_)
|
||||
slider (p, paramIndex)
|
||||
{
|
||||
startTimer (100);
|
||||
addAndMakeVisible (slider);
|
||||
@@ -44,15 +44,19 @@ public:
|
||||
owner.removeListener (this);
|
||||
}
|
||||
|
||||
void refresh()
|
||||
void refresh() override
|
||||
{
|
||||
paramHasChanged = false;
|
||||
slider.setValue (owner.getParameter (index), dontSendNotification);
|
||||
|
||||
if (slider.getThumbBeingDragged() < 0)
|
||||
slider.setValue (owner.getParameter (index), dontSendNotification);
|
||||
|
||||
slider.updateText();
|
||||
}
|
||||
|
||||
void audioProcessorChanged (AudioProcessor*) {}
|
||||
void audioProcessorChanged (AudioProcessor*) override {}
|
||||
|
||||
void audioProcessorParameterChanged (AudioProcessor*, int parameterIndex, float)
|
||||
void audioProcessorParameterChanged (AudioProcessor*, int parameterIndex, float) override
|
||||
{
|
||||
if (parameterIndex == index)
|
||||
paramHasChanged = true;
|
||||
@@ -76,27 +80,34 @@ private:
|
||||
class ParamSlider : public Slider
|
||||
{
|
||||
public:
|
||||
ParamSlider (AudioProcessor& p, const int index_)
|
||||
: owner (p),
|
||||
index (index_)
|
||||
ParamSlider (AudioProcessor& p, int paramIndex) : owner (p), index (paramIndex)
|
||||
{
|
||||
setRange (0.0, 1.0, 0.0);
|
||||
const int steps = owner.getParameterNumSteps (index);
|
||||
|
||||
if (steps > 1 && steps < 0x7fffffff)
|
||||
setRange (0.0, 1.0, 1.0 / (steps - 1.0));
|
||||
else
|
||||
setRange (0.0, 1.0);
|
||||
|
||||
setSliderStyle (Slider::LinearBar);
|
||||
setTextBoxIsEditable (false);
|
||||
setScrollWheelEnabled (false);
|
||||
setScrollWheelEnabled (true);
|
||||
}
|
||||
|
||||
void valueChanged()
|
||||
void valueChanged() override
|
||||
{
|
||||
const float newVal = (float) getValue();
|
||||
|
||||
if (owner.getParameter (index) != newVal)
|
||||
{
|
||||
owner.setParameterNotifyingHost (index, newVal);
|
||||
updateText();
|
||||
}
|
||||
}
|
||||
|
||||
String getTextFromValue (double /*value*/)
|
||||
String getTextFromValue (double /*value*/) override
|
||||
{
|
||||
return owner.getParameterText (index);
|
||||
return owner.getParameterText (index) + " " + owner.getParameterLabel (index).trimEnd();
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
+13
-5
@@ -71,18 +71,26 @@ PluginDescription& PluginDescription::operator= (const PluginDescription& other)
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool PluginDescription::isDuplicateOf (const PluginDescription& other) const
|
||||
bool PluginDescription::isDuplicateOf (const PluginDescription& other) const noexcept
|
||||
{
|
||||
return fileOrIdentifier == other.fileOrIdentifier
|
||||
&& uid == other.uid;
|
||||
}
|
||||
|
||||
static String getPluginDescSuffix (const PluginDescription& d)
|
||||
{
|
||||
return "-" + String::toHexString (d.fileOrIdentifier.hashCode())
|
||||
+ "-" + String::toHexString (d.uid);
|
||||
}
|
||||
|
||||
bool PluginDescription::matchesIdentifierString (const String& identifierString) const
|
||||
{
|
||||
return identifierString.endsWithIgnoreCase (getPluginDescSuffix (*this));
|
||||
}
|
||||
|
||||
String PluginDescription::createIdentifierString() const
|
||||
{
|
||||
return pluginFormatName
|
||||
+ "-" + name
|
||||
+ "-" + String::toHexString (fileOrIdentifier.hashCode())
|
||||
+ "-" + String::toHexString (uid);
|
||||
return pluginFormatName + "-" + name + getPluginDescSuffix (*this);
|
||||
}
|
||||
|
||||
XmlElement* PluginDescription::createXml() const
|
||||
|
||||
@@ -107,7 +107,15 @@ public:
|
||||
This isn't quite as simple as them just having the same file (because of
|
||||
shell plug-ins).
|
||||
*/
|
||||
bool isDuplicateOf (const PluginDescription& other) const;
|
||||
bool isDuplicateOf (const PluginDescription& other) const noexcept;
|
||||
|
||||
/** Return true if this description is equivalent to another one which created the
|
||||
given identifier string.
|
||||
|
||||
Note that this isn't quite as simple as them just calling createIdentifierString()
|
||||
and comparing the strings, because the identifers can differ (thanks to shell plug-ins).
|
||||
*/
|
||||
bool matchesIdentifierString (const String& identifierString) const;
|
||||
|
||||
//==============================================================================
|
||||
/** Returns a string that can be saved and used to uniquely identify the
|
||||
|
||||
@@ -46,7 +46,7 @@ PluginDescription* KnownPluginList::getTypeForFile (const String& fileOrIdentifi
|
||||
PluginDescription* KnownPluginList::getTypeForIdentifierString (const String& identifierString) const
|
||||
{
|
||||
for (int i = 0; i < types.size(); ++i)
|
||||
if (types.getUnchecked(i)->createIdentifierString() == identifierString)
|
||||
if (types.getUnchecked(i)->matchesIdentifierString (identifierString))
|
||||
return types.getUnchecked(i);
|
||||
|
||||
return nullptr;
|
||||
@@ -259,15 +259,15 @@ struct PluginSorter
|
||||
|
||||
switch (method)
|
||||
{
|
||||
case KnownPluginList::sortByCategory: diff = first->category.compareLexicographically (second->category); break;
|
||||
case KnownPluginList::sortByManufacturer: diff = first->manufacturerName.compareLexicographically (second->manufacturerName); break;
|
||||
case KnownPluginList::sortByCategory: diff = first->category.compareNatural (second->category); break;
|
||||
case KnownPluginList::sortByManufacturer: diff = first->manufacturerName.compareNatural (second->manufacturerName); break;
|
||||
case KnownPluginList::sortByFormat: diff = first->pluginFormatName.compare (second->pluginFormatName); break;
|
||||
case KnownPluginList::sortByFileSystemLocation: diff = lastPathPart (first->fileOrIdentifier).compare (lastPathPart (second->fileOrIdentifier)); break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
if (diff == 0)
|
||||
diff = first->name.compareLexicographically (second->name);
|
||||
diff = first->name.compareNatural (second->name);
|
||||
|
||||
return diff * direction;
|
||||
}
|
||||
|
||||
+167
-115
@@ -75,11 +75,10 @@ class AudioDeviceSelectorComponent::MidiInputSelectorComponentListBox : public
|
||||
private ListBoxModel
|
||||
{
|
||||
public:
|
||||
MidiInputSelectorComponentListBox (AudioDeviceManager& dm,
|
||||
const String& noItemsMessage_)
|
||||
MidiInputSelectorComponentListBox (AudioDeviceManager& dm, const String& noItems)
|
||||
: ListBox (String::empty, nullptr),
|
||||
deviceManager (dm),
|
||||
noItemsMessage (noItemsMessage_)
|
||||
noItemsMessage (noItems)
|
||||
{
|
||||
items = MidiInput::getDevices();
|
||||
|
||||
@@ -87,15 +86,12 @@ public:
|
||||
setOutlineThickness (1);
|
||||
}
|
||||
|
||||
int getNumRows()
|
||||
int getNumRows() override
|
||||
{
|
||||
return items.size();
|
||||
}
|
||||
|
||||
void paintListBoxItem (int row,
|
||||
Graphics& g,
|
||||
int width, int height,
|
||||
bool rowIsSelected)
|
||||
void paintListBoxItem (int row, Graphics& g, int width, int height, bool rowIsSelected) override
|
||||
{
|
||||
if (isPositiveAndBelow (row, items.size()))
|
||||
{
|
||||
@@ -118,7 +114,7 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
void listBoxItemClicked (int row, const MouseEvent& e)
|
||||
void listBoxItemClicked (int row, const MouseEvent& e) override
|
||||
{
|
||||
selectRow (row);
|
||||
|
||||
@@ -126,12 +122,12 @@ public:
|
||||
flipEnablement (row);
|
||||
}
|
||||
|
||||
void listBoxItemDoubleClicked (int row, const MouseEvent&)
|
||||
void listBoxItemDoubleClicked (int row, const MouseEvent&) override
|
||||
{
|
||||
flipEnablement (row);
|
||||
}
|
||||
|
||||
void returnKeyPressed (int row)
|
||||
void returnKeyPressed (int row) override
|
||||
{
|
||||
flipEnablement (row);
|
||||
}
|
||||
@@ -214,7 +210,6 @@ public:
|
||||
type.scanForDevices();
|
||||
|
||||
setup.manager->addChangeListener (this);
|
||||
updateAllControls();
|
||||
}
|
||||
|
||||
~AudioDeviceSettingsPanel()
|
||||
@@ -224,83 +219,107 @@ public:
|
||||
|
||||
void resized() override
|
||||
{
|
||||
const int lx = proportionOfWidth (0.35f);
|
||||
const int w = proportionOfWidth (0.4f);
|
||||
const int h = 24;
|
||||
const int space = 6;
|
||||
const int dh = h + space;
|
||||
int y = 0;
|
||||
|
||||
if (outputDeviceDropDown != nullptr)
|
||||
if (AudioDeviceSelectorComponent* parent = findParentComponentOfClass<AudioDeviceSelectorComponent>())
|
||||
{
|
||||
outputDeviceDropDown->setBounds (lx, y, w, h);
|
||||
Rectangle<int> r (proportionOfWidth (0.35f), 0, proportionOfWidth (0.6f), 3000);
|
||||
|
||||
if (testButton != nullptr)
|
||||
testButton->setBounds (proportionOfWidth (0.77f),
|
||||
outputDeviceDropDown->getY(),
|
||||
proportionOfWidth (0.18f),
|
||||
h);
|
||||
y += dh;
|
||||
const int maxListBoxHeight = 100;
|
||||
const int h = parent->getItemHeight();
|
||||
const int space = h / 4;
|
||||
|
||||
if (outputDeviceDropDown != nullptr)
|
||||
{
|
||||
Rectangle<int> row (r.removeFromTop (h));
|
||||
|
||||
if (testButton != nullptr)
|
||||
{
|
||||
testButton->changeWidthToFitText (h);
|
||||
testButton->setBounds (row.removeFromRight (testButton->getWidth()));
|
||||
row.removeFromRight (space);
|
||||
}
|
||||
|
||||
outputDeviceDropDown->setBounds (row);
|
||||
r.removeFromTop (space);
|
||||
}
|
||||
|
||||
if (inputDeviceDropDown != nullptr)
|
||||
{
|
||||
Rectangle<int> row (r.removeFromTop (h));
|
||||
|
||||
inputLevelMeter->setBounds (row.removeFromRight (testButton != nullptr ? testButton->getWidth() : row.getWidth() / 6));
|
||||
row.removeFromRight (space);
|
||||
inputDeviceDropDown->setBounds (row);
|
||||
r.removeFromTop (space);
|
||||
}
|
||||
|
||||
if (outputChanList != nullptr)
|
||||
{
|
||||
outputChanList->setBounds (r.removeFromTop (outputChanList->getBestHeight (maxListBoxHeight)));
|
||||
outputChanLabel->setBounds (0, outputChanList->getBounds().getCentreY() - h / 2, r.getX(), h);
|
||||
r.removeFromTop (space);
|
||||
}
|
||||
|
||||
if (inputChanList != nullptr)
|
||||
{
|
||||
inputChanList->setBounds (r.removeFromTop (inputChanList->getBestHeight (maxListBoxHeight)));
|
||||
inputChanLabel->setBounds (0, inputChanList->getBounds().getCentreY() - h / 2, r.getX(), h);
|
||||
r.removeFromTop (space);
|
||||
}
|
||||
|
||||
r.removeFromTop (space * 2);
|
||||
|
||||
if (showAdvancedSettingsButton != nullptr)
|
||||
{
|
||||
showAdvancedSettingsButton->setBounds (r.withHeight (h));
|
||||
showAdvancedSettingsButton->changeWidthToFitText();
|
||||
}
|
||||
|
||||
const bool advancedSettingsVisible = showAdvancedSettingsButton == nullptr
|
||||
|| ! showAdvancedSettingsButton->isVisible();
|
||||
|
||||
if (sampleRateDropDown != nullptr)
|
||||
{
|
||||
sampleRateDropDown->setVisible (advancedSettingsVisible);
|
||||
sampleRateDropDown->setBounds (r.removeFromTop (h));
|
||||
r.removeFromTop (space);
|
||||
}
|
||||
|
||||
if (bufferSizeDropDown != nullptr)
|
||||
{
|
||||
bufferSizeDropDown->setVisible (advancedSettingsVisible);
|
||||
bufferSizeDropDown->setBounds (r.removeFromTop (h));
|
||||
r.removeFromTop (space);
|
||||
}
|
||||
|
||||
r.removeFromTop (space);
|
||||
|
||||
if (showUIButton != nullptr || resetDeviceButton != nullptr)
|
||||
{
|
||||
Rectangle<int> buttons (r.removeFromTop (h));
|
||||
|
||||
if (showUIButton != nullptr)
|
||||
{
|
||||
showUIButton->setVisible (advancedSettingsVisible);
|
||||
showUIButton->changeWidthToFitText (h);
|
||||
showUIButton->setBounds (buttons.removeFromLeft (showUIButton->getWidth()));
|
||||
buttons.removeFromLeft (space);
|
||||
}
|
||||
|
||||
if (resetDeviceButton != nullptr)
|
||||
{
|
||||
resetDeviceButton->setVisible (advancedSettingsVisible);
|
||||
resetDeviceButton->changeWidthToFitText (h);
|
||||
resetDeviceButton->setBounds (buttons.removeFromLeft (resetDeviceButton->getWidth()));
|
||||
}
|
||||
|
||||
r.removeFromTop (space);
|
||||
}
|
||||
|
||||
setSize (getWidth(), r.getY());
|
||||
}
|
||||
|
||||
if (inputDeviceDropDown != nullptr)
|
||||
else
|
||||
{
|
||||
inputDeviceDropDown->setBounds (lx, y, w, h);
|
||||
|
||||
inputLevelMeter->setBounds (proportionOfWidth (0.77f),
|
||||
inputDeviceDropDown->getY(),
|
||||
proportionOfWidth (0.18f),
|
||||
h);
|
||||
y += dh;
|
||||
}
|
||||
|
||||
const int maxBoxHeight = 100;
|
||||
|
||||
if (outputChanList != nullptr)
|
||||
{
|
||||
const int bh = outputChanList->getBestHeight (maxBoxHeight);
|
||||
outputChanList->setBounds (lx, y, proportionOfWidth (0.55f), bh);
|
||||
y += bh + space;
|
||||
}
|
||||
|
||||
if (inputChanList != nullptr)
|
||||
{
|
||||
const int bh = inputChanList->getBestHeight (maxBoxHeight);
|
||||
inputChanList->setBounds (lx, y, proportionOfWidth (0.55f), bh);
|
||||
y += bh + space;
|
||||
}
|
||||
|
||||
y += space * 2;
|
||||
|
||||
if (showAdvancedSettingsButton != nullptr)
|
||||
{
|
||||
showAdvancedSettingsButton->changeWidthToFitText (h);
|
||||
showAdvancedSettingsButton->setTopLeftPosition (lx, y);
|
||||
}
|
||||
|
||||
if (sampleRateDropDown != nullptr)
|
||||
{
|
||||
sampleRateDropDown->setVisible (showAdvancedSettingsButton == nullptr
|
||||
|| ! showAdvancedSettingsButton->isVisible());
|
||||
|
||||
sampleRateDropDown->setBounds (lx, y, w, h);
|
||||
y += dh;
|
||||
}
|
||||
|
||||
if (bufferSizeDropDown != nullptr)
|
||||
{
|
||||
bufferSizeDropDown->setVisible (showAdvancedSettingsButton == nullptr
|
||||
|| ! showAdvancedSettingsButton->isVisible());
|
||||
bufferSizeDropDown->setBounds (lx, y, w, h);
|
||||
y += dh;
|
||||
}
|
||||
|
||||
if (showUIButton != nullptr)
|
||||
{
|
||||
showUIButton->setVisible (showAdvancedSettingsButton == nullptr
|
||||
|| ! showAdvancedSettingsButton->isVisible());
|
||||
showUIButton->changeWidthToFitText (h);
|
||||
showUIButton->setTopLeftPosition (lx, y);
|
||||
jassertfalse;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -398,6 +417,10 @@ public:
|
||||
{
|
||||
setup.manager->playTestSound();
|
||||
}
|
||||
else if (button == resetDeviceButton)
|
||||
{
|
||||
resetDevice();
|
||||
}
|
||||
}
|
||||
|
||||
void updateAllControls()
|
||||
@@ -406,6 +429,7 @@ public:
|
||||
updateInputsComboBox();
|
||||
|
||||
updateControlPanelButton();
|
||||
updateResetButton();
|
||||
|
||||
if (AudioIODevice* const currentDevice = setup.manager->getCurrentAudioDevice())
|
||||
{
|
||||
@@ -418,6 +442,7 @@ public:
|
||||
= new ChannelSelectorListBox (setup, ChannelSelectorListBox::audioOutputType,
|
||||
TRANS ("(no audio output channels found)")));
|
||||
outputChanLabel = new Label (String::empty, TRANS("Active output channels:"));
|
||||
outputChanLabel->setJustificationType (Justification::centredRight);
|
||||
outputChanLabel->attachToComponent (outputChanList, true);
|
||||
}
|
||||
|
||||
@@ -438,6 +463,7 @@ public:
|
||||
= new ChannelSelectorListBox (setup, ChannelSelectorListBox::audioInputType,
|
||||
TRANS("(no audio input channels found)")));
|
||||
inputChanLabel = new Label (String::empty, TRANS("Active input channels:"));
|
||||
inputChanLabel->setJustificationType (Justification::centredRight);
|
||||
inputChanLabel->attachToComponent (inputChanList, true);
|
||||
}
|
||||
|
||||
@@ -468,6 +494,7 @@ public:
|
||||
inputDeviceDropDown->setSelectedId (-1, dontSendNotification);
|
||||
}
|
||||
|
||||
sendLookAndFeelChange();
|
||||
resized();
|
||||
setSize (getWidth(), getLowestY() + 4);
|
||||
}
|
||||
@@ -477,6 +504,12 @@ public:
|
||||
updateAllControls();
|
||||
}
|
||||
|
||||
void resetDevice()
|
||||
{
|
||||
setup.manager->closeAudioDevice();
|
||||
setup.manager->restartLastAudioDevice();
|
||||
}
|
||||
|
||||
private:
|
||||
AudioIODeviceType& type;
|
||||
const AudioDeviceSetupDetails setup;
|
||||
@@ -485,7 +518,7 @@ private:
|
||||
ScopedPointer<Label> outputDeviceLabel, inputDeviceLabel, sampleRateLabel, bufferSizeLabel, inputChanLabel, outputChanLabel;
|
||||
ScopedPointer<TextButton> testButton;
|
||||
ScopedPointer<Component> inputLevelMeter;
|
||||
ScopedPointer<TextButton> showUIButton, showAdvancedSettingsButton;
|
||||
ScopedPointer<TextButton> showUIButton, showAdvancedSettingsButton, resetDeviceButton;
|
||||
|
||||
void showCorrectDeviceName (ComboBox* const box, const bool isInput)
|
||||
{
|
||||
@@ -532,7 +565,7 @@ private:
|
||||
|
||||
if (currentDevice != nullptr && currentDevice->hasControlPanel())
|
||||
{
|
||||
addAndMakeVisible (showUIButton = new TextButton (TRANS ("Show this device's control panel"),
|
||||
addAndMakeVisible (showUIButton = new TextButton (TRANS ("Control panel"),
|
||||
TRANS ("Opens the device's own control panel")));
|
||||
showUIButton->addListener (this);
|
||||
}
|
||||
@@ -540,6 +573,28 @@ private:
|
||||
resized();
|
||||
}
|
||||
|
||||
void updateResetButton()
|
||||
{
|
||||
if (AudioIODevice* const currentDevice = setup.manager->getCurrentAudioDevice())
|
||||
{
|
||||
if (currentDevice->hasControlPanel())
|
||||
{
|
||||
if (resetDeviceButton == nullptr)
|
||||
{
|
||||
addAndMakeVisible (resetDeviceButton = new TextButton (TRANS ("Reset device"),
|
||||
TRANS ("Resets the audio interface - sometimes needed after changing a device's properties in its custom control panel")));
|
||||
|
||||
resetDeviceButton->addListener (this);
|
||||
resized();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
resetDeviceButton = nullptr;
|
||||
}
|
||||
|
||||
void updateOutputsComboBox()
|
||||
{
|
||||
if (setup.maxNumOutputChannels > 0 || ! type.hasSeparateInputsAndOutputs())
|
||||
@@ -557,7 +612,8 @@ private:
|
||||
|
||||
if (setup.maxNumOutputChannels > 0)
|
||||
{
|
||||
addAndMakeVisible (testButton = new TextButton (TRANS("Test")));
|
||||
addAndMakeVisible (testButton = new TextButton (TRANS("Test"),
|
||||
TRANS("Plays a test tone")));
|
||||
testButton->addListener (this);
|
||||
}
|
||||
}
|
||||
@@ -918,6 +974,7 @@ AudioDeviceSelectorComponent::AudioDeviceSelectorComponent (AudioDeviceManager&
|
||||
const bool showChannelsAsStereoPairs_,
|
||||
const bool hideAdvancedOptionsWithButton_)
|
||||
: deviceManager (dm),
|
||||
itemHeight (24),
|
||||
minOutputChannels (minOutputChannels_),
|
||||
maxOutputChannels (maxOutputChannels_),
|
||||
minInputChannels (minInputChannels_),
|
||||
@@ -984,42 +1041,40 @@ AudioDeviceSelectorComponent::~AudioDeviceSelectorComponent()
|
||||
deviceManager.removeChangeListener (this);
|
||||
}
|
||||
|
||||
void AudioDeviceSelectorComponent::setItemHeight (int newItemHeight)
|
||||
{
|
||||
itemHeight = newItemHeight;
|
||||
resized();
|
||||
}
|
||||
|
||||
void AudioDeviceSelectorComponent::resized()
|
||||
{
|
||||
const int lx = proportionOfWidth (0.35f);
|
||||
const int w = proportionOfWidth (0.4f);
|
||||
const int h = 24;
|
||||
const int space = 6;
|
||||
const int dh = h + space;
|
||||
int y = 15;
|
||||
Rectangle<int> r (proportionOfWidth (0.35f), 15, proportionOfWidth (0.6f), 3000);
|
||||
const int space = itemHeight / 4;
|
||||
|
||||
if (deviceTypeDropDown != nullptr)
|
||||
{
|
||||
deviceTypeDropDown->setBounds (lx, y, proportionOfWidth (0.3f), h);
|
||||
y += dh + space * 2;
|
||||
deviceTypeDropDown->setBounds (r.removeFromTop (itemHeight));
|
||||
r.removeFromTop (space * 3);
|
||||
}
|
||||
|
||||
if (audioDeviceSettingsComp != nullptr)
|
||||
{
|
||||
audioDeviceSettingsComp->setBounds (0, y, getWidth(), audioDeviceSettingsComp->getHeight());
|
||||
y += audioDeviceSettingsComp->getHeight() + space;
|
||||
audioDeviceSettingsComp->resized();
|
||||
audioDeviceSettingsComp->setBounds (r.removeFromTop (audioDeviceSettingsComp->getHeight())
|
||||
.withX (0).withWidth (getWidth()));
|
||||
r.removeFromTop (space);
|
||||
}
|
||||
|
||||
if (midiInputsList != nullptr)
|
||||
{
|
||||
const int bh = midiInputsList->getBestHeight (jmin (h * 8, getHeight() - y - space - h));
|
||||
midiInputsList->setBounds (lx, y, w, bh);
|
||||
y += bh + space;
|
||||
midiInputsList->setBounds (r.removeFromTop (midiInputsList->getBestHeight (jmin (itemHeight * 8,
|
||||
getHeight() - r.getY() - space - itemHeight))));
|
||||
r.removeFromTop (space);
|
||||
}
|
||||
|
||||
if (midiOutputSelector != nullptr)
|
||||
midiOutputSelector->setBounds (lx, y, w, h);
|
||||
}
|
||||
|
||||
void AudioDeviceSelectorComponent::childBoundsChanged (Component* child)
|
||||
{
|
||||
if (child == audioDeviceSettingsComp)
|
||||
resized();
|
||||
midiOutputSelector->setBounds (r.removeFromTop (itemHeight));
|
||||
}
|
||||
|
||||
void AudioDeviceSelectorComponent::comboBoxChanged (ComboBox* comboBoxThatHasChanged)
|
||||
@@ -1069,13 +1124,10 @@ void AudioDeviceSelectorComponent::updateAllControls()
|
||||
details.maxNumOutputChannels = maxOutputChannels;
|
||||
details.useStereoPairs = showChannelsAsStereoPairs;
|
||||
|
||||
audioDeviceSettingsComp = new AudioDeviceSettingsPanel (*type, details, hideAdvancedOptionsWithButton);
|
||||
|
||||
if (audioDeviceSettingsComp != nullptr)
|
||||
{
|
||||
addAndMakeVisible (audioDeviceSettingsComp);
|
||||
audioDeviceSettingsComp->resized();
|
||||
}
|
||||
AudioDeviceSettingsPanel* sp = new AudioDeviceSettingsPanel (*type, details, hideAdvancedOptionsWithButton);
|
||||
audioDeviceSettingsComp = sp;
|
||||
addAndMakeVisible (sp);
|
||||
sp->updateAllControls();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -75,11 +75,15 @@ public:
|
||||
/** The device manager that this component is controlling */
|
||||
AudioDeviceManager& deviceManager;
|
||||
|
||||
/** Sets the standard height used for items in the panel. */
|
||||
void setItemHeight (int itemHeight);
|
||||
|
||||
/** Returns the standard height used for items in the panel. */
|
||||
int getItemHeight() const noexcept { return itemHeight; }
|
||||
|
||||
//==============================================================================
|
||||
/** @internal */
|
||||
void resized() override;
|
||||
/** @internal */
|
||||
void childBoundsChanged (Component*) override;
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
@@ -87,6 +91,7 @@ private:
|
||||
ScopedPointer<Label> deviceTypeDropDownLabel;
|
||||
ScopedPointer<Component> audioDeviceSettingsComp;
|
||||
String audioDeviceSettingsCompType;
|
||||
int itemHeight;
|
||||
const int minOutputChannels, maxOutputChannels, minInputChannels, maxInputChannels;
|
||||
const bool showChannelsAsStereoPairs;
|
||||
const bool hideAdvancedOptionsWithButton;
|
||||
|
||||
@@ -39,10 +39,10 @@ struct AudioThumbnail::MinMaxValue
|
||||
inline char getMinValue() const noexcept { return values[0]; }
|
||||
inline char getMaxValue() const noexcept { return values[1]; }
|
||||
|
||||
inline void setFloat (const float newMin, const float newMax) noexcept
|
||||
inline void setFloat (Range<float> newRange) noexcept
|
||||
{
|
||||
values[0] = (char) jlimit (-128, 127, roundFloatToInt (newMin * 127.0f));
|
||||
values[1] = (char) jlimit (-128, 127, roundFloatToInt (newMax * 127.0f));
|
||||
values[0] = (char) jlimit (-128, 127, roundFloatToInt (newRange.getStart() * 127.0f));
|
||||
values[1] = (char) jlimit (-128, 127, roundFloatToInt (newRange.getEnd() * 127.0f));
|
||||
|
||||
if (values[0] == values[1])
|
||||
{
|
||||
@@ -115,7 +115,7 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
void getLevels (int64 startSample, int numSamples, Array<float>& levels)
|
||||
void getLevels (int64 startSample, int numSamples, Array<Range<float> >& levels)
|
||||
{
|
||||
const ScopedLock sl (readerLock);
|
||||
|
||||
@@ -132,11 +132,10 @@ public:
|
||||
|
||||
if (reader != nullptr)
|
||||
{
|
||||
float l[4] = { 0 };
|
||||
reader->readMaxLevels (startSample, numSamples, l[0], l[1], l[2], l[3]);
|
||||
if (levels.size() < (int) reader->numChannels)
|
||||
levels.insertMultiple (0, Range<float>(), (int) (reader->numChannels - levels.size()));
|
||||
|
||||
levels.clearQuick();
|
||||
levels.addArray ((const float*) l, 4);
|
||||
reader->readMaxLevels (startSample, numSamples, levels.getRawDataPointer(), (int) reader->numChannels);
|
||||
|
||||
lastReaderUseTime = Time::getMillisecondCounter();
|
||||
}
|
||||
@@ -202,8 +201,8 @@ public:
|
||||
|
||||
private:
|
||||
AudioThumbnail& owner;
|
||||
ScopedPointer <InputSource> source;
|
||||
ScopedPointer <AudioFormatReader> reader;
|
||||
ScopedPointer<InputSource> source;
|
||||
ScopedPointer<AudioFormatReader> reader;
|
||||
CriticalSection readerLock;
|
||||
uint32 lastReaderUseTime;
|
||||
|
||||
@@ -230,23 +229,26 @@ private:
|
||||
const int lastThumbIndex = sampleToThumbSample (startSample + numToDo);
|
||||
const int numThumbSamps = lastThumbIndex - firstThumbIndex;
|
||||
|
||||
HeapBlock<MinMaxValue> levelData ((size_t) numThumbSamps * 2);
|
||||
MinMaxValue* levels[2] = { levelData, levelData + numThumbSamps };
|
||||
HeapBlock<MinMaxValue> levelData ((size_t) numThumbSamps * numChannels);
|
||||
HeapBlock<MinMaxValue*> levels (numChannels);
|
||||
|
||||
for (int i = 0; i < (int) numChannels; ++i)
|
||||
levels[i] = levelData + i * numThumbSamps;
|
||||
|
||||
HeapBlock<Range<float> > levelsRead (numChannels);
|
||||
|
||||
for (int i = 0; i < numThumbSamps; ++i)
|
||||
{
|
||||
float lowestLeft, highestLeft, lowestRight, highestRight;
|
||||
reader->readMaxLevels ((firstThumbIndex + i) * owner.samplesPerThumbSample,
|
||||
owner.samplesPerThumbSample, levelsRead, numChannels);
|
||||
|
||||
reader->readMaxLevels ((firstThumbIndex + i) * owner.samplesPerThumbSample, owner.samplesPerThumbSample,
|
||||
lowestLeft, highestLeft, lowestRight, highestRight);
|
||||
|
||||
levels[0][i].setFloat (lowestLeft, highestLeft);
|
||||
levels[1][i].setFloat (lowestRight, highestRight);
|
||||
for (int j = 0; j < (int) numChannels; ++j)
|
||||
levels[j][i].setFloat (levelsRead[j]);
|
||||
}
|
||||
|
||||
{
|
||||
const ScopedUnlock su (readerLock);
|
||||
owner.setLevels (levels, firstThumbIndex, 2, numThumbSamps);
|
||||
owner.setLevels (levels, firstThumbIndex, (int) numChannels, numThumbSamps);
|
||||
}
|
||||
|
||||
numSamplesFinished += numToDo;
|
||||
@@ -342,7 +344,7 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
Array <MinMaxValue> data;
|
||||
Array<MinMaxValue> data;
|
||||
int peakLevel;
|
||||
|
||||
void ensureSize (const int thumbSamples)
|
||||
@@ -391,6 +393,7 @@ public:
|
||||
const MinMaxValue* cacheData = getData (channelNum, clip.getX() - area.getX());
|
||||
|
||||
RectangleList<float> waveform;
|
||||
waveform.ensureStorageAllocated (clip.getWidth());
|
||||
|
||||
float x = (float) clip.getX();
|
||||
|
||||
@@ -414,7 +417,7 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
Array <MinMaxValue> data;
|
||||
Array<MinMaxValue> data;
|
||||
double cachedStart, cachedTimePerPixel;
|
||||
int numChannelsCached, numSamplesCached;
|
||||
bool cacheNeedsRefilling;
|
||||
@@ -451,7 +454,7 @@ private:
|
||||
if (timePerPixel * rate <= sampsPerThumbSample && levelData != nullptr)
|
||||
{
|
||||
int sample = roundToInt (startTime * rate);
|
||||
Array<float> levels;
|
||||
Array<Range<float> > levels;
|
||||
|
||||
int i;
|
||||
for (i = 0; i < numSamples; ++i)
|
||||
@@ -469,11 +472,10 @@ private:
|
||||
{
|
||||
levelData->getLevels (sample, jmax (1, nextSample - sample), levels);
|
||||
|
||||
const int totalChans = jmin (levels.size() / 2, numChannelsCached);
|
||||
const int totalChans = jmin (levels.size(), numChannelsCached);
|
||||
|
||||
for (int chan = 0; chan < totalChans; ++chan)
|
||||
getData (chan, i)->setFloat (levels.getUnchecked (chan * 2),
|
||||
levels.getUnchecked (chan * 2 + 1));
|
||||
getData (chan, i)->setFloat (levels.getReference (chan));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -713,8 +715,7 @@ void AudioThumbnail::addBlock (const int64 startSample, const AudioSampleBuffer&
|
||||
for (int i = 0; i < numToDo; ++i)
|
||||
{
|
||||
const int start = i * samplesPerThumbSample;
|
||||
Range<float> range (FloatVectorOperations::findMinAndMax (sourceData + start, jmin (samplesPerThumbSample, numSamples - start)));
|
||||
dest[i].setFloat (range.getStart(), range.getEnd());
|
||||
dest[i].setFloat (FloatVectorOperations::findMinAndMax (sourceData + start, jmin (samplesPerThumbSample, numSamples - start)));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -816,7 +816,7 @@ void MidiKeyboardComponent::timerCallback()
|
||||
const Array<MouseInputSource>& mouseSources = Desktop::getInstance().getMouseSources();
|
||||
|
||||
for (MouseInputSource* mi = mouseSources.begin(), * const e = mouseSources.end(); mi != e; ++mi)
|
||||
updateNoteUnderMouse (getLocalPoint (nullptr, mi->getScreenPosition()), mi->isDragging(), mi->getIndex());
|
||||
updateNoteUnderMouse (getLocalPoint (nullptr, mi->getScreenPosition()).roundToInt(), mi->isDragging(), mi->getIndex());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"id": "juce_audio_utils",
|
||||
"name": "JUCE extra audio utility classes",
|
||||
"version": "3.0.5",
|
||||
"version": "3.0.8",
|
||||
"description": "Classes for audio-related GUI and miscellaneous tasks.",
|
||||
"website": "http://www.juce.com/juce",
|
||||
"license": "GPL/Commercial",
|
||||
|
||||
@@ -35,7 +35,7 @@ AbstractFifo::AbstractFifo (const int capacity) noexcept
|
||||
AbstractFifo::~AbstractFifo() {}
|
||||
|
||||
int AbstractFifo::getTotalSize() const noexcept { return bufferSize; }
|
||||
int AbstractFifo::getFreeSpace() const noexcept { return bufferSize - getNumReady(); }
|
||||
int AbstractFifo::getFreeSpace() const noexcept { return bufferSize - getNumReady() - 1; }
|
||||
|
||||
int AbstractFifo::getNumReady() const noexcept
|
||||
{
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
- it must be able to be relocated in memory by a memcpy without this causing any problems - so
|
||||
objects whose functionality relies on external pointers or references to themselves can not be used.
|
||||
|
||||
You can of course have an array of pointers to any kind of object, e.g. Array <MyClass*>, but if
|
||||
You can of course have an array of pointers to any kind of object, e.g. Array<MyClass*>, but if
|
||||
you do this, the array doesn't take any ownership of the objects - see the OwnedArray class or the
|
||||
ReferenceCountedArray class for more powerful ways of holding lists of objects.
|
||||
|
||||
@@ -65,8 +65,7 @@ private:
|
||||
public:
|
||||
//==============================================================================
|
||||
/** Creates an empty array. */
|
||||
Array() noexcept
|
||||
: numUsed (0)
|
||||
Array() noexcept : numUsed (0)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ DynamicObject::DynamicObject()
|
||||
}
|
||||
|
||||
DynamicObject::DynamicObject (const DynamicObject& other)
|
||||
: properties (other.properties)
|
||||
: ReferenceCountedObject(), properties (other.properties)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -85,16 +85,9 @@ void DynamicObject::clear()
|
||||
|
||||
void DynamicObject::cloneAllProperties()
|
||||
{
|
||||
for (LinkedListPointer<NamedValueSet::NamedValue>* i = &(properties.values);;)
|
||||
{
|
||||
if (NamedValueSet::NamedValue* const v = i->get())
|
||||
{
|
||||
v->value = v->value.clone();
|
||||
i = &(v->nextListItem);
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
for (int i = properties.size(); --i >= 0;)
|
||||
if (var* v = properties.getVarPointerAt (i))
|
||||
*v = v->clone();
|
||||
}
|
||||
|
||||
DynamicObject::Ptr DynamicObject::clone()
|
||||
@@ -110,32 +103,27 @@ void DynamicObject::writeAsJSON (OutputStream& out, const int indentLevel, const
|
||||
if (! allOnOneLine)
|
||||
out << newLine;
|
||||
|
||||
for (LinkedListPointer<NamedValueSet::NamedValue>* i = &(properties.values);;)
|
||||
const int numValues = properties.size();
|
||||
|
||||
for (int i = 0; i < numValues; ++i)
|
||||
{
|
||||
if (NamedValueSet::NamedValue* const v = i->get())
|
||||
if (! allOnOneLine)
|
||||
JSONFormatter::writeSpaces (out, indentLevel + JSONFormatter::indentSize);
|
||||
|
||||
out << '"';
|
||||
JSONFormatter::writeString (out, properties.getName (i));
|
||||
out << "\": ";
|
||||
JSONFormatter::write (out, properties.getValueAt (i), indentLevel + JSONFormatter::indentSize, allOnOneLine);
|
||||
|
||||
if (i < numValues - 1)
|
||||
{
|
||||
if (! allOnOneLine)
|
||||
JSONFormatter::writeSpaces (out, indentLevel + JSONFormatter::indentSize);
|
||||
|
||||
out << '"';
|
||||
JSONFormatter::writeString (out, v->name);
|
||||
out << "\": ";
|
||||
JSONFormatter::write (out, v->value, indentLevel + JSONFormatter::indentSize, allOnOneLine);
|
||||
|
||||
if (v->nextListItem.get() != nullptr)
|
||||
{
|
||||
if (allOnOneLine)
|
||||
out << ", ";
|
||||
else
|
||||
out << ',' << newLine;
|
||||
}
|
||||
else if (! allOnOneLine)
|
||||
out << newLine;
|
||||
|
||||
i = &(v->nextListItem);
|
||||
if (allOnOneLine)
|
||||
out << ", ";
|
||||
else
|
||||
out << ',' << newLine;
|
||||
}
|
||||
else
|
||||
break;
|
||||
else if (! allOnOneLine)
|
||||
out << newLine;
|
||||
}
|
||||
|
||||
if (! allOnOneLine)
|
||||
|
||||
@@ -58,7 +58,7 @@ public:
|
||||
virtual bool hasProperty (const Identifier& propertyName) const;
|
||||
|
||||
/** Returns a named property.
|
||||
This returns a void if no such property exists.
|
||||
This returns var::null if no such property exists.
|
||||
*/
|
||||
virtual var getProperty (const Identifier& propertyName) const;
|
||||
|
||||
|
||||
@@ -26,53 +26,37 @@
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
NamedValueSet::NamedValue::NamedValue() noexcept
|
||||
struct NamedValueSet::NamedValue
|
||||
{
|
||||
}
|
||||
NamedValue() noexcept {}
|
||||
NamedValue (Identifier n, const var& v) : name (n), value (v) {}
|
||||
NamedValue (const NamedValue& other) : name (other.name), value (other.value) {}
|
||||
|
||||
inline NamedValueSet::NamedValue::NamedValue (Identifier n, const var& v)
|
||||
: name (n), value (v)
|
||||
{
|
||||
}
|
||||
#if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
|
||||
NamedValue (NamedValue&& other) noexcept
|
||||
: name (static_cast<Identifier&&> (other.name)),
|
||||
value (static_cast<var&&> (other.value))
|
||||
{
|
||||
}
|
||||
|
||||
NamedValueSet::NamedValue::NamedValue (const NamedValue& other)
|
||||
: name (other.name), value (other.value)
|
||||
{
|
||||
}
|
||||
NamedValue (Identifier n, var&& v) : name (n), value (static_cast<var&&> (v))
|
||||
{
|
||||
}
|
||||
|
||||
NamedValueSet::NamedValue& NamedValueSet::NamedValue::operator= (const NamedValueSet::NamedValue& other)
|
||||
{
|
||||
name = other.name;
|
||||
value = other.value;
|
||||
return *this;
|
||||
}
|
||||
NamedValue& operator= (NamedValue&& other) noexcept
|
||||
{
|
||||
name = static_cast<Identifier&&> (other.name);
|
||||
value = static_cast<var&&> (other.value);
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
|
||||
NamedValueSet::NamedValue::NamedValue (NamedValue&& other) noexcept
|
||||
: nextListItem (static_cast<LinkedListPointer<NamedValue>&&> (other.nextListItem)),
|
||||
name (static_cast<Identifier&&> (other.name)),
|
||||
value (static_cast<var&&> (other.value))
|
||||
{
|
||||
}
|
||||
bool operator== (const NamedValue& other) const noexcept { return name == other.name && value == other.value; }
|
||||
bool operator!= (const NamedValue& other) const noexcept { return ! operator== (other); }
|
||||
|
||||
inline NamedValueSet::NamedValue::NamedValue (Identifier n, var&& v)
|
||||
: name (n), value (static_cast<var&&> (v))
|
||||
{
|
||||
}
|
||||
|
||||
NamedValueSet::NamedValue& NamedValueSet::NamedValue::operator= (NamedValue&& other) noexcept
|
||||
{
|
||||
nextListItem = static_cast<LinkedListPointer<NamedValue>&&> (other.nextListItem);
|
||||
name = static_cast<Identifier&&> (other.name);
|
||||
value = static_cast<var&&> (other.value);
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool NamedValueSet::NamedValue::operator== (const NamedValueSet::NamedValue& other) const noexcept
|
||||
{
|
||||
return name == other.name && value == other.value;
|
||||
}
|
||||
Identifier name;
|
||||
var value;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
NamedValueSet::NamedValueSet() noexcept
|
||||
@@ -80,20 +64,20 @@ NamedValueSet::NamedValueSet() noexcept
|
||||
}
|
||||
|
||||
NamedValueSet::NamedValueSet (const NamedValueSet& other)
|
||||
: values (other.values)
|
||||
{
|
||||
values.addCopyOfList (other.values);
|
||||
}
|
||||
|
||||
NamedValueSet& NamedValueSet::operator= (const NamedValueSet& other)
|
||||
{
|
||||
clear();
|
||||
values.addCopyOfList (other.values);
|
||||
values = other.values;
|
||||
return *this;
|
||||
}
|
||||
|
||||
#if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
|
||||
NamedValueSet::NamedValueSet (NamedValueSet&& other) noexcept
|
||||
: values (static_cast <LinkedListPointer<NamedValue>&&> (other.values))
|
||||
: values (static_cast <Array<NamedValue>&&> (other.values))
|
||||
{
|
||||
}
|
||||
|
||||
@@ -104,31 +88,18 @@ NamedValueSet& NamedValueSet::operator= (NamedValueSet&& other) noexcept
|
||||
}
|
||||
#endif
|
||||
|
||||
NamedValueSet::~NamedValueSet()
|
||||
NamedValueSet::~NamedValueSet() noexcept
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
void NamedValueSet::clear()
|
||||
{
|
||||
values.deleteAll();
|
||||
values.clear();
|
||||
}
|
||||
|
||||
bool NamedValueSet::operator== (const NamedValueSet& other) const
|
||||
{
|
||||
const NamedValue* i1 = values;
|
||||
const NamedValue* i2 = other.values;
|
||||
|
||||
while (i1 != nullptr && i2 != nullptr)
|
||||
{
|
||||
if (! (*i1 == *i2))
|
||||
return false;
|
||||
|
||||
i1 = i1->nextListItem;
|
||||
i2 = i2->nextListItem;
|
||||
}
|
||||
|
||||
return true;
|
||||
return values == other.values;
|
||||
}
|
||||
|
||||
bool NamedValueSet::operator!= (const NamedValueSet& other) const
|
||||
@@ -141,16 +112,15 @@ int NamedValueSet::size() const noexcept
|
||||
return values.size();
|
||||
}
|
||||
|
||||
const var& NamedValueSet::operator[] (Identifier name) const
|
||||
const var& NamedValueSet::operator[] (const Identifier& name) const noexcept
|
||||
{
|
||||
for (NamedValue* i = values; i != nullptr; i = i->nextListItem)
|
||||
if (i->name == name)
|
||||
return i->value;
|
||||
if (const var* v = getVarPointer (name))
|
||||
return *v;
|
||||
|
||||
return var::null;
|
||||
}
|
||||
|
||||
var NamedValueSet::getWithDefault (Identifier name, const var& defaultReturnValue) const
|
||||
var NamedValueSet::getWithDefault (const Identifier& name, const var& defaultReturnValue) const
|
||||
{
|
||||
if (const var* const v = getVarPointer (name))
|
||||
return *v;
|
||||
@@ -158,9 +128,9 @@ var NamedValueSet::getWithDefault (Identifier name, const var& defaultReturnValu
|
||||
return defaultReturnValue;
|
||||
}
|
||||
|
||||
var* NamedValueSet::getVarPointer (Identifier name) const noexcept
|
||||
var* NamedValueSet::getVarPointer (const Identifier& name) const noexcept
|
||||
{
|
||||
for (NamedValue* i = values; i != nullptr; i = i->nextListItem)
|
||||
for (NamedValue* e = values.end(), *i = values.begin(); i != e; ++i)
|
||||
if (i->name == name)
|
||||
return &(i->value);
|
||||
|
||||
@@ -170,145 +140,121 @@ var* NamedValueSet::getVarPointer (Identifier name) const noexcept
|
||||
#if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
|
||||
bool NamedValueSet::set (Identifier name, var&& newValue)
|
||||
{
|
||||
LinkedListPointer<NamedValue>* i = &values;
|
||||
|
||||
while (i->get() != nullptr)
|
||||
if (var* const v = getVarPointer (name))
|
||||
{
|
||||
NamedValue* const v = i->get();
|
||||
if (v->equalsWithSameType (newValue))
|
||||
return false;
|
||||
|
||||
if (v->name == name)
|
||||
{
|
||||
if (v->value.equalsWithSameType (newValue))
|
||||
return false;
|
||||
|
||||
v->value = static_cast <var&&> (newValue);
|
||||
return true;
|
||||
}
|
||||
|
||||
i = &(v->nextListItem);
|
||||
*v = static_cast<var&&> (newValue);
|
||||
return true;
|
||||
}
|
||||
|
||||
i->insertNext (new NamedValue (name, static_cast <var&&> (newValue)));
|
||||
values.add (NamedValue (name, static_cast<var&&> (newValue)));
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool NamedValueSet::set (Identifier name, const var& newValue)
|
||||
{
|
||||
LinkedListPointer<NamedValue>* i = &values;
|
||||
|
||||
while (i->get() != nullptr)
|
||||
if (var* const v = getVarPointer (name))
|
||||
{
|
||||
NamedValue* const v = i->get();
|
||||
if (v->equalsWithSameType (newValue))
|
||||
return false;
|
||||
|
||||
if (v->name == name)
|
||||
{
|
||||
if (v->value.equalsWithSameType (newValue))
|
||||
return false;
|
||||
|
||||
v->value = newValue;
|
||||
return true;
|
||||
}
|
||||
|
||||
i = &(v->nextListItem);
|
||||
*v = newValue;
|
||||
return true;
|
||||
}
|
||||
|
||||
i->insertNext (new NamedValue (name, newValue));
|
||||
values.add (NamedValue (name, newValue));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NamedValueSet::contains (Identifier name) const
|
||||
bool NamedValueSet::contains (const Identifier& name) const noexcept
|
||||
{
|
||||
return getVarPointer (name) != nullptr;
|
||||
}
|
||||
|
||||
int NamedValueSet::indexOf (Identifier name) const noexcept
|
||||
int NamedValueSet::indexOf (const Identifier& name) const noexcept
|
||||
{
|
||||
int index = 0;
|
||||
const int numValues = values.size();
|
||||
|
||||
for (NamedValue* i = values; i != nullptr; i = i->nextListItem)
|
||||
{
|
||||
if (i->name == name)
|
||||
return index;
|
||||
|
||||
++index;
|
||||
}
|
||||
for (int i = 0; i < numValues; ++i)
|
||||
if (values.getReference(i).name == name)
|
||||
return i;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool NamedValueSet::remove (Identifier name)
|
||||
bool NamedValueSet::remove (const Identifier& name)
|
||||
{
|
||||
LinkedListPointer<NamedValue>* i = &values;
|
||||
const int numValues = values.size();
|
||||
|
||||
for (;;)
|
||||
for (int i = 0; i < numValues; ++i)
|
||||
{
|
||||
NamedValue* const v = i->get();
|
||||
|
||||
if (v == nullptr)
|
||||
break;
|
||||
|
||||
if (v->name == name)
|
||||
if (values.getReference(i).name == name)
|
||||
{
|
||||
delete i->removeNext();
|
||||
values.remove (i);
|
||||
return true;
|
||||
}
|
||||
|
||||
i = &(v->nextListItem);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Identifier NamedValueSet::getName (const int index) const
|
||||
Identifier NamedValueSet::getName (const int index) const noexcept
|
||||
{
|
||||
const NamedValue* const v = values[index];
|
||||
jassert (v != nullptr);
|
||||
return v->name;
|
||||
if (isPositiveAndBelow (index, values.size()))
|
||||
return values.getReference (index).name;
|
||||
|
||||
jassertfalse;
|
||||
return Identifier();
|
||||
}
|
||||
|
||||
const var& NamedValueSet::getValueAt (const int index) const
|
||||
const var& NamedValueSet::getValueAt (const int index) const noexcept
|
||||
{
|
||||
const NamedValue* const v = values[index];
|
||||
jassert (v != nullptr);
|
||||
return v->value;
|
||||
if (isPositiveAndBelow (index, values.size()))
|
||||
return values.getReference (index).value;
|
||||
|
||||
jassertfalse;
|
||||
return var::null;
|
||||
}
|
||||
|
||||
var* NamedValueSet::getVarPointerAt (int index) const noexcept
|
||||
{
|
||||
if (isPositiveAndBelow (index, values.size()))
|
||||
return &(values.getReference (index).value);
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void NamedValueSet::setFromXmlAttributes (const XmlElement& xml)
|
||||
{
|
||||
clear();
|
||||
LinkedListPointer<NamedValue>::Appender appender (values);
|
||||
values.clearQuick();
|
||||
|
||||
const int numAtts = xml.getNumAttributes(); // xxx inefficient - should write an att iterator..
|
||||
|
||||
for (int i = 0; i < numAtts; ++i)
|
||||
for (const XmlElement::XmlAttributeNode* att = xml.attributes; att != nullptr; att = att->nextListItem)
|
||||
{
|
||||
const String& name = xml.getAttributeName (i);
|
||||
const String& value = xml.getAttributeValue (i);
|
||||
|
||||
if (name.startsWith ("base64:"))
|
||||
if (att->name.toString().startsWith ("base64:"))
|
||||
{
|
||||
MemoryBlock mb;
|
||||
|
||||
if (mb.fromBase64Encoding (value))
|
||||
if (mb.fromBase64Encoding (att->value))
|
||||
{
|
||||
appender.append (new NamedValue (name.substring (7), var (mb)));
|
||||
values.add (NamedValue (att->name.toString().substring (7), var (mb)));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
appender.append (new NamedValue (name, var (value)));
|
||||
values.add (NamedValue (att->name, var (att->value)));
|
||||
}
|
||||
}
|
||||
|
||||
void NamedValueSet::copyToXmlAttributes (XmlElement& xml) const
|
||||
{
|
||||
for (NamedValue* i = values; i != nullptr; i = i->nextListItem)
|
||||
for (NamedValue* e = values.end(), *i = values.begin(); i != e; ++i)
|
||||
{
|
||||
if (const MemoryBlock* mb = i->value.getBinaryData())
|
||||
{
|
||||
xml.setAttribute ("base64:" + i->name.toString(),
|
||||
mb->toBase64Encoding());
|
||||
xml.setAttribute ("base64:" + i->name.toString(), mb->toBase64Encoding());
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -54,7 +54,7 @@ public:
|
||||
#endif
|
||||
|
||||
/** Destructor. */
|
||||
~NamedValueSet();
|
||||
~NamedValueSet() noexcept;
|
||||
|
||||
bool operator== (const NamedValueSet&) const;
|
||||
bool operator!= (const NamedValueSet&) const;
|
||||
@@ -67,12 +67,12 @@ public:
|
||||
If the name isn't found, this will return a void variant.
|
||||
@see getProperty
|
||||
*/
|
||||
const var& operator[] (Identifier name) const;
|
||||
const var& operator[] (const Identifier& name) const noexcept;
|
||||
|
||||
/** Tries to return the named value, but if no such value is found, this will
|
||||
instead return the supplied default value.
|
||||
*/
|
||||
var getWithDefault (Identifier name, const var& defaultReturnValue) const;
|
||||
var getWithDefault (const Identifier& name, const var& defaultReturnValue) const;
|
||||
|
||||
/** Changes or adds a named value.
|
||||
@returns true if a value was changed or added; false if the
|
||||
@@ -89,38 +89,42 @@ public:
|
||||
#endif
|
||||
|
||||
/** Returns true if the set contains an item with the specified name. */
|
||||
bool contains (Identifier name) const;
|
||||
bool contains (const Identifier& name) const noexcept;
|
||||
|
||||
/** Removes a value from the set.
|
||||
@returns true if a value was removed; false if there was no value
|
||||
with the name that was given.
|
||||
*/
|
||||
bool remove (Identifier name);
|
||||
bool remove (const Identifier& name);
|
||||
|
||||
/** Returns the name of the value at a given index.
|
||||
The index must be between 0 and size() - 1.
|
||||
*/
|
||||
Identifier getName (int index) const;
|
||||
Identifier getName (int index) const noexcept;
|
||||
|
||||
/** Returns the value of the item at a given index.
|
||||
The index must be between 0 and size() - 1.
|
||||
*/
|
||||
const var& getValueAt (int index) const;
|
||||
|
||||
/** Returns the index of the given name, or -1 if it's not found. */
|
||||
int indexOf (Identifier name) const noexcept;
|
||||
|
||||
/** Removes all values. */
|
||||
void clear();
|
||||
|
||||
//==============================================================================
|
||||
/** Returns a pointer to the var that holds a named value, or null if there is
|
||||
no value with this name.
|
||||
|
||||
Do not use this method unless you really need access to the internal var object
|
||||
for some reason - for normal reading and writing always prefer operator[]() and set().
|
||||
*/
|
||||
var* getVarPointer (Identifier name) const noexcept;
|
||||
var* getVarPointer (const Identifier& name) const noexcept;
|
||||
|
||||
/** Returns the value of the item at a given index.
|
||||
The index must be between 0 and size() - 1.
|
||||
*/
|
||||
const var& getValueAt (int index) const noexcept;
|
||||
|
||||
/** Returns the value of the item at a given index.
|
||||
The index must be between 0 and size() - 1, or this will return a nullptr
|
||||
*/
|
||||
var* getVarPointerAt (int index) const noexcept;
|
||||
|
||||
/** Returns the index of the given name, or -1 if it's not found. */
|
||||
int indexOf (const Identifier& name) const noexcept;
|
||||
|
||||
/** Removes all values. */
|
||||
void clear();
|
||||
|
||||
//==============================================================================
|
||||
/** Sets properties to the values of all of an XML element's attributes. */
|
||||
@@ -133,32 +137,8 @@ public:
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
class NamedValue
|
||||
{
|
||||
public:
|
||||
NamedValue() noexcept;
|
||||
NamedValue (const NamedValue&);
|
||||
NamedValue (Identifier, const var&);
|
||||
NamedValue& operator= (const NamedValue&);
|
||||
#if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
|
||||
NamedValue (NamedValue&&) noexcept;
|
||||
NamedValue (Identifier, var&&);
|
||||
NamedValue& operator= (NamedValue&&) noexcept;
|
||||
#endif
|
||||
bool operator== (const NamedValue&) const noexcept;
|
||||
|
||||
LinkedListPointer<NamedValue> nextListItem;
|
||||
Identifier name;
|
||||
var value;
|
||||
|
||||
private:
|
||||
JUCE_LEAK_DETECTOR (NamedValue)
|
||||
};
|
||||
|
||||
friend class LinkedListPointer<NamedValue>;
|
||||
LinkedListPointer<NamedValue> values;
|
||||
|
||||
friend class DynamicObject;
|
||||
struct NamedValue;
|
||||
Array<NamedValue> values;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -830,7 +830,7 @@ public:
|
||||
This will use a comparator object to sort the elements into order. The object
|
||||
passed must have a method of the form:
|
||||
@code
|
||||
int compareElements (ElementType first, ElementType second);
|
||||
int compareElements (ElementType* first, ElementType* second);
|
||||
@endcode
|
||||
|
||||
..and this method must return:
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
The template parameter specifies the class of the object you want to point to - the easiest
|
||||
way to make a class reference-countable is to simply make it inherit from ReferenceCountedObject
|
||||
or SingleThreadedReferenceCountedObject, but if you need to, you can roll your own reference-countable
|
||||
class by implementing a set of mathods called incReferenceCount(), decReferenceCount(), and
|
||||
class by implementing a set of methods called incReferenceCount(), decReferenceCount(), and
|
||||
decReferenceCountWithoutDeleting(). See ReferenceCountedObject for examples of how these methods
|
||||
should behave.
|
||||
|
||||
@@ -72,7 +72,7 @@ public:
|
||||
const ScopedLockType lock (other.getLock());
|
||||
numUsed = other.size();
|
||||
data.setAllocatedSize (numUsed);
|
||||
memcpy (data.elements, other.getRawDataPointer(), numUsed * sizeof (ObjectClass*));
|
||||
memcpy (data.elements, other.getRawDataPointer(), (size_t) numUsed * sizeof (ObjectClass*));
|
||||
|
||||
for (int i = numUsed; --i >= 0;)
|
||||
if (ObjectClass* o = data.elements[i])
|
||||
|
||||
@@ -476,7 +476,7 @@ bool File::loadFileAsData (MemoryBlock& destBlock) const
|
||||
return false;
|
||||
|
||||
FileInputStream in (*this);
|
||||
return in.openedOk() && getSize() == in.readIntoMemoryBlock (destBlock);
|
||||
return in.openedOk() && getSize() == (int64) in.readIntoMemoryBlock (destBlock);
|
||||
}
|
||||
|
||||
String File::loadFileAsString() const
|
||||
|
||||
@@ -361,6 +361,14 @@ public:
|
||||
*/
|
||||
File getLinkedTarget() const;
|
||||
|
||||
/** Returns a unique identifier for the file, if one is available.
|
||||
|
||||
Depending on the OS and file-system, this may be a unix inode number or
|
||||
a win32 file identifier, or 0 if it fails to find one. The number will
|
||||
be unique on the filesystem, but not globally.
|
||||
*/
|
||||
uint64 getFileIdentifier() const;
|
||||
|
||||
//==============================================================================
|
||||
/** Returns the last modification time of this file.
|
||||
|
||||
@@ -836,6 +844,11 @@ public:
|
||||
/** In a plugin, this will return the path of the host executable. */
|
||||
hostApplicationPath,
|
||||
|
||||
#if JUCE_WINDOWS
|
||||
/** On a Windows machine, returns the location of the Windows/System32 folder. */
|
||||
windowsSystemDirectory,
|
||||
#endif
|
||||
|
||||
/** The directory in which applications normally get installed.
|
||||
So on windows, this would be something like "c:\program files", on the
|
||||
Mac "/Applications", or "/usr" on linux.
|
||||
|
||||
@@ -28,41 +28,34 @@
|
||||
|
||||
int64 juce_fileSetPosition (void* handle, int64 pos);
|
||||
|
||||
|
||||
//==============================================================================
|
||||
FileInputStream::FileInputStream (const File& f)
|
||||
: file (f),
|
||||
fileHandle (nullptr),
|
||||
currentPosition (0),
|
||||
status (Result::ok()),
|
||||
needToSeek (true)
|
||||
status (Result::ok())
|
||||
{
|
||||
openHandle();
|
||||
}
|
||||
|
||||
FileInputStream::~FileInputStream()
|
||||
{
|
||||
closeHandle();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
int64 FileInputStream::getTotalLength()
|
||||
{
|
||||
// You should always check that a stream opened successfully before using it!
|
||||
jassert (openedOk());
|
||||
|
||||
return file.getSize();
|
||||
}
|
||||
|
||||
int FileInputStream::read (void* buffer, int bytesToRead)
|
||||
{
|
||||
// You should always check that a stream opened successfully before using it!
|
||||
jassert (openedOk());
|
||||
|
||||
// The buffer should never be null, and a negative size is probably a
|
||||
// sign that something is broken!
|
||||
jassert (buffer != nullptr && bytesToRead >= 0);
|
||||
|
||||
if (needToSeek)
|
||||
{
|
||||
if (juce_fileSetPosition (fileHandle, currentPosition) < 0)
|
||||
return 0;
|
||||
|
||||
needToSeek = false;
|
||||
}
|
||||
|
||||
const size_t num = readInternal (buffer, (size_t) bytesToRead);
|
||||
currentPosition += num;
|
||||
|
||||
@@ -81,15 +74,11 @@ int64 FileInputStream::getPosition()
|
||||
|
||||
bool FileInputStream::setPosition (int64 pos)
|
||||
{
|
||||
// You should always check that a stream opened successfully before using it!
|
||||
jassert (openedOk());
|
||||
|
||||
if (pos != currentPosition)
|
||||
{
|
||||
pos = jlimit ((int64) 0, getTotalLength(), pos);
|
||||
currentPosition = juce_fileSetPosition (fileHandle, pos);
|
||||
|
||||
needToSeek |= (currentPosition != pos);
|
||||
currentPosition = pos;
|
||||
}
|
||||
|
||||
return true;
|
||||
return currentPosition == pos;
|
||||
}
|
||||
|
||||
@@ -40,10 +40,11 @@ class JUCE_API FileInputStream : public InputStream
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
/** Creates a FileInputStream.
|
||||
/** Creates a FileInputStream to read from the given file.
|
||||
|
||||
@param fileToRead the file to read from - if the file can't be accessed for some
|
||||
reason, then the stream will just contain no data
|
||||
After creating a FileInputStream, you should use openedOk() or failedToOpen()
|
||||
to make sure that it's OK before trying to read from it! If it failed, you
|
||||
can call getStatus() to get more error information.
|
||||
*/
|
||||
explicit FileInputStream (const File& fileToRead);
|
||||
|
||||
@@ -73,24 +74,23 @@ public:
|
||||
|
||||
//==============================================================================
|
||||
int64 getTotalLength() override;
|
||||
int read (void* destBuffer, int maxBytesToRead) override;
|
||||
int read (void*, int) override;
|
||||
bool isExhausted() override;
|
||||
int64 getPosition() override;
|
||||
bool setPosition (int64 pos) override;
|
||||
bool setPosition (int64) override;
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
File file;
|
||||
const File file;
|
||||
void* fileHandle;
|
||||
int64 currentPosition;
|
||||
Result status;
|
||||
bool needToSeek;
|
||||
|
||||
void openHandle();
|
||||
void closeHandle();
|
||||
size_t readInternal (void* buffer, size_t numBytes);
|
||||
size_t readInternal (void*, size_t);
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FileInputStream)
|
||||
};
|
||||
|
||||
|
||||
#endif // JUCE_FILEINPUTSTREAM_H_INCLUDED
|
||||
|
||||
@@ -26,32 +26,7 @@
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
WildcardFileFilter::WildcardFileFilter (const String& fileWildcardPatterns,
|
||||
const String& directoryWildcardPatterns,
|
||||
const String& desc)
|
||||
: FileFilter (desc.isEmpty() ? fileWildcardPatterns
|
||||
: (desc + " (" + fileWildcardPatterns + ")"))
|
||||
{
|
||||
parse (fileWildcardPatterns, fileWildcards);
|
||||
parse (directoryWildcardPatterns, directoryWildcards);
|
||||
}
|
||||
|
||||
WildcardFileFilter::~WildcardFileFilter()
|
||||
{
|
||||
}
|
||||
|
||||
bool WildcardFileFilter::isFileSuitable (const File& file) const
|
||||
{
|
||||
return match (file, fileWildcards);
|
||||
}
|
||||
|
||||
bool WildcardFileFilter::isDirectorySuitable (const File& file) const
|
||||
{
|
||||
return match (file, directoryWildcards);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void WildcardFileFilter::parse (const String& pattern, StringArray& result)
|
||||
static void parseWildcard (const String& pattern, StringArray& result)
|
||||
{
|
||||
result.addTokens (pattern.toLowerCase(), ";,", "\"'");
|
||||
|
||||
@@ -65,7 +40,7 @@ void WildcardFileFilter::parse (const String& pattern, StringArray& result)
|
||||
result.set (i, "*");
|
||||
}
|
||||
|
||||
bool WildcardFileFilter::match (const File& file, const StringArray& wildcards)
|
||||
static bool matchWildcard (const File& file, const StringArray& wildcards)
|
||||
{
|
||||
const String filename (file.getFileName());
|
||||
|
||||
@@ -75,3 +50,27 @@ bool WildcardFileFilter::match (const File& file, const StringArray& wildcards)
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
WildcardFileFilter::WildcardFileFilter (const String& fileWildcardPatterns,
|
||||
const String& directoryWildcardPatterns,
|
||||
const String& desc)
|
||||
: FileFilter (desc.isEmpty() ? fileWildcardPatterns
|
||||
: (desc + " (" + fileWildcardPatterns + ")"))
|
||||
{
|
||||
parseWildcard (fileWildcardPatterns, fileWildcards);
|
||||
parseWildcard (directoryWildcardPatterns, directoryWildcards);
|
||||
}
|
||||
|
||||
WildcardFileFilter::~WildcardFileFilter()
|
||||
{
|
||||
}
|
||||
|
||||
bool WildcardFileFilter::isFileSuitable (const File& file) const
|
||||
{
|
||||
return matchWildcard (file, fileWildcards);
|
||||
}
|
||||
|
||||
bool WildcardFileFilter::isDirectorySuitable (const File& file) const
|
||||
{
|
||||
return matchWildcard (file, directoryWildcards);
|
||||
}
|
||||
|
||||
@@ -75,12 +75,8 @@ private:
|
||||
//==============================================================================
|
||||
StringArray fileWildcards, directoryWildcards;
|
||||
|
||||
static void parse (const String& pattern, StringArray& result);
|
||||
static bool match (const File& file, const StringArray& wildcards);
|
||||
|
||||
JUCE_LEAK_DETECTOR (WildcardFileFilter)
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif // JUCE_WILDCARDFILEFILTER_H_INCLUDED
|
||||
|
||||
@@ -243,9 +243,9 @@ private:
|
||||
if (r.failed())
|
||||
return r;
|
||||
|
||||
const String propertyName (propertyNameVar.toString());
|
||||
const Identifier propertyName (propertyNameVar.toString());
|
||||
|
||||
if (propertyName.isNotEmpty())
|
||||
if (propertyName.isValid())
|
||||
{
|
||||
t = t.findEndOfWhitespace();
|
||||
oldT = t;
|
||||
|
||||
@@ -102,6 +102,7 @@ struct JavascriptEngine::RootObject : public DynamicObject
|
||||
static bool isNumericOrUndefined (const var& v) { return v.isInt() || v.isDouble() || v.isInt64() || v.isBool() || v.isUndefined(); }
|
||||
static int64 getOctalValue (const String& s) { BigInteger b; b.parseString (s, 8); return b.toInt64(); }
|
||||
static Identifier getPrototypeIdentifier() { static const Identifier i ("prototype"); return i; }
|
||||
static var* getPropertyPointer (DynamicObject* o, Identifier i) { return o->getProperties().getVarPointer (i); }
|
||||
|
||||
//==============================================================================
|
||||
struct CodeLocation
|
||||
@@ -139,13 +140,13 @@ struct JavascriptEngine::RootObject : public DynamicObject
|
||||
{
|
||||
if (DynamicObject* o = targetObject.getDynamicObject())
|
||||
{
|
||||
if (var* prop = o->getProperties().getVarPointer (functionName))
|
||||
if (const var* prop = getPropertyPointer (o, functionName))
|
||||
return *prop;
|
||||
|
||||
for (DynamicObject* p = o->getProperty (getPrototypeIdentifier()).getDynamicObject(); p != nullptr;
|
||||
p = p->getProperty (getPrototypeIdentifier()).getDynamicObject())
|
||||
{
|
||||
if (var* prop = p->getProperties().getVarPointer (functionName))
|
||||
if (const var* prop = getPropertyPointer (p, functionName))
|
||||
return *prop;
|
||||
}
|
||||
}
|
||||
@@ -168,14 +169,14 @@ struct JavascriptEngine::RootObject : public DynamicObject
|
||||
var* findRootClassProperty (Identifier className, Identifier propName) const
|
||||
{
|
||||
if (DynamicObject* cls = root->getProperty (className).getDynamicObject())
|
||||
return cls->getProperties().getVarPointer (propName);
|
||||
return getPropertyPointer (cls, propName);
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
var findSymbolInParentScopes (Identifier name) const
|
||||
{
|
||||
if (var* v = scope->getProperties().getVarPointer (name))
|
||||
if (const var* v = getPropertyPointer (scope, name))
|
||||
return *v;
|
||||
|
||||
return parent != nullptr ? parent->findSymbolInParentScopes (name)
|
||||
@@ -184,13 +185,11 @@ struct JavascriptEngine::RootObject : public DynamicObject
|
||||
|
||||
bool findAndInvokeMethod (Identifier function, const var::NativeFunctionArgs& args, var& result) const
|
||||
{
|
||||
const NamedValueSet& props = scope->getProperties();
|
||||
|
||||
DynamicObject* target = args.thisObject.getDynamicObject();
|
||||
|
||||
if (target == nullptr || target == scope)
|
||||
{
|
||||
if (const var* m = props.getVarPointer (function))
|
||||
if (const var* m = getPropertyPointer (scope, function))
|
||||
{
|
||||
if (FunctionObject* fo = dynamic_cast<FunctionObject*> (m->getObject()))
|
||||
{
|
||||
@@ -200,6 +199,8 @@ struct JavascriptEngine::RootObject : public DynamicObject
|
||||
}
|
||||
}
|
||||
|
||||
const NamedValueSet& props = scope->getProperties();
|
||||
|
||||
for (int i = 0; i < props.size(); ++i)
|
||||
if (DynamicObject* o = props.getValueAt (i).getDynamicObject())
|
||||
if (Scope (this, root, o).findAndInvokeMethod (function, args, result))
|
||||
@@ -353,7 +354,7 @@ struct JavascriptEngine::RootObject : public DynamicObject
|
||||
|
||||
void assign (const Scope& s, const var& newValue) const override
|
||||
{
|
||||
if (var* v = s.scope->getProperties().getVarPointer (name))
|
||||
if (var* v = getPropertyPointer (s.scope, name))
|
||||
*v = newValue;
|
||||
else
|
||||
s.root->setProperty (name, newValue);
|
||||
@@ -378,7 +379,7 @@ struct JavascriptEngine::RootObject : public DynamicObject
|
||||
}
|
||||
|
||||
if (DynamicObject* o = p.getDynamicObject())
|
||||
if (var* v = o->getProperties().getVarPointer (child))
|
||||
if (const var* v = getPropertyPointer (o, child))
|
||||
return *v;
|
||||
|
||||
return var::undefined();
|
||||
@@ -543,14 +544,14 @@ struct JavascriptEngine::RootObject : public DynamicObject
|
||||
struct DivideOp : public BinaryOperator
|
||||
{
|
||||
DivideOp (const CodeLocation& l, ExpPtr& a, ExpPtr& b) noexcept : BinaryOperator (l, a, b, TokenTypes::divide) {}
|
||||
var getWithDoubles (double a, double b) const override { return a / b; }
|
||||
var getWithInts (int64 a, int64 b) const override { return a / b; }
|
||||
var getWithDoubles (double a, double b) const override { return b != 0 ? a / b : std::numeric_limits<double>::infinity(); }
|
||||
var getWithInts (int64 a, int64 b) const override { return b != 0 ? var (a / (double) b) : var (std::numeric_limits<double>::infinity()); }
|
||||
};
|
||||
|
||||
struct ModuloOp : public BinaryOperator
|
||||
{
|
||||
ModuloOp (const CodeLocation& l, ExpPtr& a, ExpPtr& b) noexcept : BinaryOperator (l, a, b, TokenTypes::modulo) {}
|
||||
var getWithInts (int64 a, int64 b) const override { return a % b; }
|
||||
var getWithInts (int64 a, int64 b) const override { return b != 0 ? var (a % b) : var (std::numeric_limits<double>::infinity()); }
|
||||
};
|
||||
|
||||
struct BitwiseOrOp : public BinaryOperator
|
||||
@@ -768,7 +769,7 @@ struct JavascriptEngine::RootObject : public DynamicObject
|
||||
{
|
||||
FunctionObject() noexcept {}
|
||||
|
||||
FunctionObject (const FunctionObject& other) : functionCode (other.functionCode)
|
||||
FunctionObject (const FunctionObject& other) : DynamicObject(), functionCode (other.functionCode)
|
||||
{
|
||||
ExpressionTreeBuilder tb (functionCode);
|
||||
tb.parseFunctionParamsAndBody (*this);
|
||||
@@ -843,7 +844,7 @@ struct JavascriptEngine::RootObject : public DynamicObject
|
||||
String::CharPointerType end (p);
|
||||
while (isIdentifierBody (*++end)) {}
|
||||
|
||||
const size_t len = end - p;
|
||||
const size_t len = (size_t) (end - p);
|
||||
#define JUCE_JS_COMPARE_KEYWORD(name, str) if (len == sizeof (str) - 1 && matchToken (TokenTypes::name, len)) return TokenTypes::name;
|
||||
JUCE_JS_KEYWORDS (JUCE_JS_COMPARE_KEYWORD)
|
||||
|
||||
@@ -1145,8 +1146,14 @@ struct JavascriptEngine::RootObject : public DynamicObject
|
||||
match (TokenTypes::semicolon);
|
||||
}
|
||||
|
||||
s->iterator = parseExpression();
|
||||
match (TokenTypes::closeParen);
|
||||
if (matchIf (TokenTypes::closeParen))
|
||||
s->iterator = new Statement (location);
|
||||
else
|
||||
{
|
||||
s->iterator = parseExpression();
|
||||
match (TokenTypes::closeParen);
|
||||
}
|
||||
|
||||
s->body = parseStatement();
|
||||
return s.release();
|
||||
}
|
||||
@@ -1555,6 +1562,7 @@ struct JavascriptEngine::RootObject : public DynamicObject
|
||||
setMethod ("log", Math_log); setMethod ("log10", Math_log10);
|
||||
setMethod ("exp", Math_exp); setMethod ("pow", Math_pow);
|
||||
setMethod ("sqr", Math_sqr); setMethod ("sqrt", Math_sqrt);
|
||||
setMethod ("ceil", Math_ceil); setMethod ("floor", Math_floor);
|
||||
}
|
||||
|
||||
static var Math_pi (Args) { return double_Pi; }
|
||||
@@ -1587,6 +1595,8 @@ struct JavascriptEngine::RootObject : public DynamicObject
|
||||
static var Math_pow (Args a) { return pow (getDouble (a, 0), getDouble (a, 1)); }
|
||||
static var Math_sqr (Args a) { double x = getDouble (a, 0); return x * x; }
|
||||
static var Math_sqrt (Args a) { return std::sqrt (getDouble (a, 0)); }
|
||||
static var Math_ceil (Args a) { return std::ceil (getDouble (a, 0)); }
|
||||
static var Math_floor (Args a) { return std::floor (getDouble (a, 0)); }
|
||||
|
||||
static Identifier getClassName() { static const Identifier i ("Math"); return i; }
|
||||
template <typename Type> static Type sign (Type n) noexcept { return n > 0 ? (Type) 1 : (n < 0 ? (Type) -1 : 0); }
|
||||
@@ -1649,7 +1659,7 @@ JavascriptEngine::JavascriptEngine() : maximumExecutionTime (15.0), root (new R
|
||||
|
||||
JavascriptEngine::~JavascriptEngine() {}
|
||||
|
||||
void JavascriptEngine::prepareTimeout() const { root->timeout = Time::getCurrentTime() + maximumExecutionTime; }
|
||||
void JavascriptEngine::prepareTimeout() const noexcept { root->timeout = Time::getCurrentTime() + maximumExecutionTime; }
|
||||
|
||||
void JavascriptEngine::registerNativeObject (Identifier name, DynamicObject* object)
|
||||
{
|
||||
@@ -1705,6 +1715,11 @@ var JavascriptEngine::callFunction (Identifier function, const var::NativeFuncti
|
||||
return returnVal;
|
||||
}
|
||||
|
||||
const NamedValueSet& JavascriptEngine::getRootObjectProperties() const noexcept
|
||||
{
|
||||
return root->getProperties();
|
||||
}
|
||||
|
||||
#if JUCE_MSVC
|
||||
#pragma warning (pop)
|
||||
#endif
|
||||
|
||||
@@ -96,10 +96,13 @@ public:
|
||||
*/
|
||||
RelativeTime maximumExecutionTime;
|
||||
|
||||
/** Provides access to the set of properties of the root namespace object. */
|
||||
const NamedValueSet& getRootObjectProperties() const noexcept;
|
||||
|
||||
private:
|
||||
JUCE_PUBLIC_IN_DLL_BUILD (struct RootObject)
|
||||
ReferenceCountedObjectPtr<RootObject> root;
|
||||
void prepareTimeout() const;
|
||||
const ReferenceCountedObjectPtr<RootObject> root;
|
||||
void prepareTimeout() const noexcept;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (JavascriptEngine)
|
||||
};
|
||||
|
||||
@@ -53,6 +53,8 @@
|
||||
|
||||
#if JUCE_WINDOWS
|
||||
#include <ctime>
|
||||
|
||||
#define _WINSOCK_DEPRECATED_NO_WARNINGS 1
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
|
||||
@@ -79,6 +81,7 @@
|
||||
|
||||
#if JUCE_LINUX
|
||||
#include <langinfo.h>
|
||||
#include <ifaddrs.h>
|
||||
#endif
|
||||
|
||||
#include <pwd.h>
|
||||
|
||||
@@ -194,6 +194,7 @@ extern JUCE_API void JUCE_CALLTYPE logAssertion (const char* file, int line) noe
|
||||
#include "threads/juce_ScopedLock.h"
|
||||
#include "threads/juce_CriticalSection.h"
|
||||
#include "maths/juce_Range.h"
|
||||
#include "maths/juce_NormalisableRange.h"
|
||||
#include "containers/juce_ElementComparator.h"
|
||||
#include "containers/juce_ArrayAllocationBase.h"
|
||||
#include "containers/juce_Array.h"
|
||||
@@ -244,6 +245,7 @@ extern JUCE_API void JUCE_CALLTYPE logAssertion (const char* file, int line) noe
|
||||
#include "misc/juce_Uuid.h"
|
||||
#include "misc/juce_WindowsRegistry.h"
|
||||
#include "system/juce_PlatformDefs.h"
|
||||
#include "system/juce_CompilerSupport.h"
|
||||
#include "system/juce_SystemStats.h"
|
||||
#include "threads/juce_ChildProcess.h"
|
||||
#include "threads/juce_DynamicLibrary.h"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"id": "juce_core",
|
||||
"name": "JUCE core classes",
|
||||
"version": "3.0.5",
|
||||
"version": "3.0.8",
|
||||
"description": "The essential set of basic JUCE classes, as required by all the other JUCE modules. Includes text, container, memory, threading and i/o functionality.",
|
||||
"website": "http://www.juce.com/juce",
|
||||
"license": "ISC Permissive",
|
||||
|
||||
@@ -307,41 +307,28 @@ void BigInteger::negate() noexcept
|
||||
negative = (! negative) && ! isZero();
|
||||
}
|
||||
|
||||
#if JUCE_USE_INTRINSICS && ! defined (__INTEL_COMPILER)
|
||||
#if JUCE_USE_MSVC_INTRINSICS && ! defined (__INTEL_COMPILER)
|
||||
#pragma intrinsic (_BitScanReverse)
|
||||
#endif
|
||||
|
||||
namespace BitFunctions
|
||||
inline static int highestBitInInt (uint32 n) noexcept
|
||||
{
|
||||
inline int countBitsInInt32 (uint32 n) noexcept
|
||||
{
|
||||
n -= ((n >> 1) & 0x55555555);
|
||||
n = (((n >> 2) & 0x33333333) + (n & 0x33333333));
|
||||
n = (((n >> 4) + n) & 0x0f0f0f0f);
|
||||
n += (n >> 8);
|
||||
n += (n >> 16);
|
||||
return (int) (n & 0x3f);
|
||||
}
|
||||
jassert (n != 0); // (the built-in functions may not work for n = 0)
|
||||
|
||||
inline int highestBitInInt (uint32 n) noexcept
|
||||
{
|
||||
jassert (n != 0); // (the built-in functions may not work for n = 0)
|
||||
|
||||
#if JUCE_GCC
|
||||
return 31 - __builtin_clz (n);
|
||||
#elif JUCE_USE_INTRINSICS
|
||||
unsigned long highest;
|
||||
_BitScanReverse (&highest, n);
|
||||
return (int) highest;
|
||||
#else
|
||||
n |= (n >> 1);
|
||||
n |= (n >> 2);
|
||||
n |= (n >> 4);
|
||||
n |= (n >> 8);
|
||||
n |= (n >> 16);
|
||||
return countBitsInInt32 (n >> 1);
|
||||
#endif
|
||||
}
|
||||
#if JUCE_GCC
|
||||
return 31 - __builtin_clz (n);
|
||||
#elif JUCE_USE_MSVC_INTRINSICS
|
||||
unsigned long highest;
|
||||
_BitScanReverse (&highest, n);
|
||||
return (int) highest;
|
||||
#else
|
||||
n |= (n >> 1);
|
||||
n |= (n >> 2);
|
||||
n |= (n >> 4);
|
||||
n |= (n >> 8);
|
||||
n |= (n >> 16);
|
||||
return countBitsInInt32 (n >> 1);
|
||||
#endif
|
||||
}
|
||||
|
||||
int BigInteger::countNumberOfSetBits() const noexcept
|
||||
@@ -349,7 +336,7 @@ int BigInteger::countNumberOfSetBits() const noexcept
|
||||
int total = 0;
|
||||
|
||||
for (int i = (int) bitToIndex (highestBit) + 1; --i >= 0;)
|
||||
total += BitFunctions::countBitsInInt32 (values[i]);
|
||||
total += countNumberOfBits (values[i]);
|
||||
|
||||
return total;
|
||||
}
|
||||
@@ -361,7 +348,7 @@ int BigInteger::getHighestBit() const noexcept
|
||||
const uint32 n = values[i];
|
||||
|
||||
if (n != 0)
|
||||
return BitFunctions::highestBitInInt (n) + (i << 5);
|
||||
return highestBitInInt (n) + (i << 5);
|
||||
}
|
||||
|
||||
return -1;
|
||||
|
||||
@@ -364,6 +364,11 @@ inline int roundToInt (const FloatType value) noexcept
|
||||
#endif
|
||||
}
|
||||
|
||||
inline int roundToInt (int value) noexcept
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
#if JUCE_MSVC
|
||||
#ifndef __INTEL_COMPILER
|
||||
#pragma float_control (pop)
|
||||
@@ -438,6 +443,23 @@ inline int nextPowerOfTwo (int n) noexcept
|
||||
return n + 1;
|
||||
}
|
||||
|
||||
/** Returns the number of bits in a 32-bit integer. */
|
||||
inline int countNumberOfBits (uint32 n) noexcept
|
||||
{
|
||||
n -= ((n >> 1) & 0x55555555);
|
||||
n = (((n >> 2) & 0x33333333) + (n & 0x33333333));
|
||||
n = (((n >> 4) + n) & 0x0f0f0f0f);
|
||||
n += (n >> 8);
|
||||
n += (n >> 16);
|
||||
return (int) (n & 0x3f);
|
||||
}
|
||||
|
||||
/** Returns the number of bits in a 64-bit integer. */
|
||||
inline int countNumberOfBits (uint64 n) noexcept
|
||||
{
|
||||
return countNumberOfBits ((uint32) n) + countNumberOfBits ((uint32) (n >> 32));
|
||||
}
|
||||
|
||||
/** Performs a modulo operation, but can cope with the dividend being negative.
|
||||
The divisor must be greater than zero.
|
||||
*/
|
||||
|
||||
@@ -77,6 +77,13 @@ public:
|
||||
: Range (position2, position1);
|
||||
}
|
||||
|
||||
/** Returns a range with a given start and length. */
|
||||
static Range withStartAndLength (const ValueType startValue, const ValueType length) noexcept
|
||||
{
|
||||
jassert (length >= ValueType());
|
||||
return Range (startValue, startValue + length);
|
||||
}
|
||||
|
||||
/** Returns a range with the specified start position and a length of zero. */
|
||||
static Range emptyRange (const ValueType start) noexcept
|
||||
{
|
||||
|
||||
@@ -218,7 +218,7 @@ private:
|
||||
#else
|
||||
#define JUCE_ATOMICS_WINDOWS 1 // Windows with intrinsics
|
||||
|
||||
#if JUCE_USE_INTRINSICS
|
||||
#if JUCE_USE_MSVC_INTRINSICS
|
||||
#ifndef __INTEL_COMPILER
|
||||
#pragma intrinsic (_InterlockedExchange, _InterlockedIncrement, _InterlockedDecrement, _InterlockedCompareExchange, \
|
||||
_InterlockedCompareExchange64, _InterlockedExchangeAdd, _ReadWriteBarrier)
|
||||
|
||||
@@ -87,16 +87,16 @@ public:
|
||||
|
||||
//==============================================================================
|
||||
/** Converts 3 little-endian bytes into a signed 24-bit value (which is sign-extended to 32 bits). */
|
||||
static int littleEndian24Bit (const char* bytes) noexcept;
|
||||
static int littleEndian24Bit (const void* bytes) noexcept;
|
||||
|
||||
/** Converts 3 big-endian bytes into a signed 24-bit value (which is sign-extended to 32 bits). */
|
||||
static int bigEndian24Bit (const char* bytes) noexcept;
|
||||
static int bigEndian24Bit (const void* bytes) noexcept;
|
||||
|
||||
/** Copies a 24-bit number to 3 little-endian bytes. */
|
||||
static void littleEndian24BitToChars (int value, char* destBytes) noexcept;
|
||||
static void littleEndian24BitToChars (int value, void* destBytes) noexcept;
|
||||
|
||||
/** Copies a 24-bit number to 3 big-endian bytes. */
|
||||
static void bigEndian24BitToChars (int value, char* destBytes) noexcept;
|
||||
static void bigEndian24BitToChars (int value, void* destBytes) noexcept;
|
||||
|
||||
//==============================================================================
|
||||
/** Returns true if the current CPU is big-endian. */
|
||||
@@ -110,16 +110,16 @@ private:
|
||||
|
||||
|
||||
//==============================================================================
|
||||
#if JUCE_USE_INTRINSICS && ! defined (__INTEL_COMPILER)
|
||||
#if JUCE_USE_MSVC_INTRINSICS && ! defined (__INTEL_COMPILER)
|
||||
#pragma intrinsic (_byteswap_ulong)
|
||||
#endif
|
||||
|
||||
inline uint16 ByteOrder::swap (uint16 n) noexcept
|
||||
{
|
||||
#if JUCE_USE_INTRINSICSxxx // agh - the MS compiler has an internal error when you try to use this intrinsic!
|
||||
return static_cast <uint16> (_byteswap_ushort (n));
|
||||
#if JUCE_USE_MSVC_INTRINSICSxxx // agh - the MS compiler has an internal error when you try to use this intrinsic!
|
||||
return static_cast<uint16> (_byteswap_ushort (n));
|
||||
#else
|
||||
return static_cast <uint16> ((n << 8) | (n >> 8));
|
||||
return static_cast<uint16> ((n << 8) | (n >> 8));
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -130,7 +130,7 @@ inline uint32 ByteOrder::swap (uint32 n) noexcept
|
||||
#elif JUCE_GCC && JUCE_INTEL && ! JUCE_NO_INLINE_ASM
|
||||
asm("bswap %%eax" : "=a"(n) : "a"(n));
|
||||
return n;
|
||||
#elif JUCE_USE_INTRINSICS
|
||||
#elif JUCE_USE_MSVC_INTRINSICS
|
||||
return _byteswap_ulong (n);
|
||||
#elif JUCE_MSVC && ! JUCE_NO_INLINE_ASM
|
||||
__asm {
|
||||
@@ -150,7 +150,7 @@ inline uint64 ByteOrder::swap (uint64 value) noexcept
|
||||
{
|
||||
#if JUCE_MAC || JUCE_IOS
|
||||
return OSSwapInt64 (value);
|
||||
#elif JUCE_USE_INTRINSICS
|
||||
#elif JUCE_USE_MSVC_INTRINSICS
|
||||
return _byteswap_uint64 (value);
|
||||
#else
|
||||
return (((int64) swap ((uint32) value)) << 32) | swap ((uint32) (value >> 32));
|
||||
@@ -164,12 +164,12 @@ inline uint64 ByteOrder::swap (uint64 value) noexcept
|
||||
inline uint16 ByteOrder::swapIfLittleEndian (const uint16 v) noexcept { return swap (v); }
|
||||
inline uint32 ByteOrder::swapIfLittleEndian (const uint32 v) noexcept { return swap (v); }
|
||||
inline uint64 ByteOrder::swapIfLittleEndian (const uint64 v) noexcept { return swap (v); }
|
||||
inline uint32 ByteOrder::littleEndianInt (const void* const bytes) noexcept { return *static_cast <const uint32*> (bytes); }
|
||||
inline uint64 ByteOrder::littleEndianInt64 (const void* const bytes) noexcept { return *static_cast <const uint64*> (bytes); }
|
||||
inline uint16 ByteOrder::littleEndianShort (const void* const bytes) noexcept { return *static_cast <const uint16*> (bytes); }
|
||||
inline uint32 ByteOrder::bigEndianInt (const void* const bytes) noexcept { return swap (*static_cast <const uint32*> (bytes)); }
|
||||
inline uint64 ByteOrder::bigEndianInt64 (const void* const bytes) noexcept { return swap (*static_cast <const uint64*> (bytes)); }
|
||||
inline uint16 ByteOrder::bigEndianShort (const void* const bytes) noexcept { return swap (*static_cast <const uint16*> (bytes)); }
|
||||
inline uint32 ByteOrder::littleEndianInt (const void* const bytes) noexcept { return *static_cast<const uint32*> (bytes); }
|
||||
inline uint64 ByteOrder::littleEndianInt64 (const void* const bytes) noexcept { return *static_cast<const uint64*> (bytes); }
|
||||
inline uint16 ByteOrder::littleEndianShort (const void* const bytes) noexcept { return *static_cast<const uint16*> (bytes); }
|
||||
inline uint32 ByteOrder::bigEndianInt (const void* const bytes) noexcept { return swap (*static_cast<const uint32*> (bytes)); }
|
||||
inline uint64 ByteOrder::bigEndianInt64 (const void* const bytes) noexcept { return swap (*static_cast<const uint64*> (bytes)); }
|
||||
inline uint16 ByteOrder::bigEndianShort (const void* const bytes) noexcept { return swap (*static_cast<const uint16*> (bytes)); }
|
||||
inline bool ByteOrder::isBigEndian() noexcept { return false; }
|
||||
#else
|
||||
inline uint16 ByteOrder::swapIfBigEndian (const uint16 v) noexcept { return swap (v); }
|
||||
@@ -178,19 +178,19 @@ inline uint64 ByteOrder::swap (uint64 value) noexcept
|
||||
inline uint16 ByteOrder::swapIfLittleEndian (const uint16 v) noexcept { return v; }
|
||||
inline uint32 ByteOrder::swapIfLittleEndian (const uint32 v) noexcept { return v; }
|
||||
inline uint64 ByteOrder::swapIfLittleEndian (const uint64 v) noexcept { return v; }
|
||||
inline uint32 ByteOrder::littleEndianInt (const void* const bytes) noexcept { return swap (*static_cast <const uint32*> (bytes)); }
|
||||
inline uint64 ByteOrder::littleEndianInt64 (const void* const bytes) noexcept { return swap (*static_cast <const uint64*> (bytes)); }
|
||||
inline uint16 ByteOrder::littleEndianShort (const void* const bytes) noexcept { return swap (*static_cast <const uint16*> (bytes)); }
|
||||
inline uint32 ByteOrder::bigEndianInt (const void* const bytes) noexcept { return *static_cast <const uint32*> (bytes); }
|
||||
inline uint64 ByteOrder::bigEndianInt64 (const void* const bytes) noexcept { return *static_cast <const uint64*> (bytes); }
|
||||
inline uint16 ByteOrder::bigEndianShort (const void* const bytes) noexcept { return *static_cast <const uint16*> (bytes); }
|
||||
inline uint32 ByteOrder::littleEndianInt (const void* const bytes) noexcept { return swap (*static_cast<const uint32*> (bytes)); }
|
||||
inline uint64 ByteOrder::littleEndianInt64 (const void* const bytes) noexcept { return swap (*static_cast<const uint64*> (bytes)); }
|
||||
inline uint16 ByteOrder::littleEndianShort (const void* const bytes) noexcept { return swap (*static_cast<const uint16*> (bytes)); }
|
||||
inline uint32 ByteOrder::bigEndianInt (const void* const bytes) noexcept { return *static_cast<const uint32*> (bytes); }
|
||||
inline uint64 ByteOrder::bigEndianInt64 (const void* const bytes) noexcept { return *static_cast<const uint64*> (bytes); }
|
||||
inline uint16 ByteOrder::bigEndianShort (const void* const bytes) noexcept { return *static_cast<const uint16*> (bytes); }
|
||||
inline bool ByteOrder::isBigEndian() noexcept { return true; }
|
||||
#endif
|
||||
|
||||
inline int ByteOrder::littleEndian24Bit (const char* const bytes) noexcept { return (((int) bytes[2]) << 16) | (((int) (uint8) bytes[1]) << 8) | ((int) (uint8) bytes[0]); }
|
||||
inline int ByteOrder::bigEndian24Bit (const char* const bytes) noexcept { return (((int) bytes[0]) << 16) | (((int) (uint8) bytes[1]) << 8) | ((int) (uint8) bytes[2]); }
|
||||
inline void ByteOrder::littleEndian24BitToChars (const int value, char* const destBytes) noexcept { destBytes[0] = (char)(value & 0xff); destBytes[1] = (char)((value >> 8) & 0xff); destBytes[2] = (char)((value >> 16) & 0xff); }
|
||||
inline void ByteOrder::bigEndian24BitToChars (const int value, char* const destBytes) noexcept { destBytes[0] = (char)((value >> 16) & 0xff); destBytes[1] = (char)((value >> 8) & 0xff); destBytes[2] = (char)(value & 0xff); }
|
||||
inline int ByteOrder::littleEndian24Bit (const void* const bytes) noexcept { return (((int) static_cast<const int8*> (bytes)[2]) << 16) | (((int) static_cast<const uint8*> (bytes)[1]) << 8) | ((int) static_cast<const uint8*> (bytes)[0]); }
|
||||
inline int ByteOrder::bigEndian24Bit (const void* const bytes) noexcept { return (((int) static_cast<const int8*> (bytes)[0]) << 16) | (((int) static_cast<const uint8*> (bytes)[1]) << 8) | ((int) static_cast<const uint8*> (bytes)[2]); }
|
||||
inline void ByteOrder::littleEndian24BitToChars (const int value, void* const destBytes) noexcept { static_cast<uint8*> (destBytes)[0] = (uint8) value; static_cast<uint8*> (destBytes)[1] = (uint8) (value >> 8); static_cast<uint8*> (destBytes)[2] = (uint8) (value >> 16); }
|
||||
inline void ByteOrder::bigEndian24BitToChars (const int value, void* const destBytes) noexcept { static_cast<uint8*> (destBytes)[0] = (uint8) (value >> 16); static_cast<uint8*> (destBytes)[1] = (uint8) (value >> 8); static_cast<uint8*> (destBytes)[2] = (uint8) value; }
|
||||
|
||||
|
||||
#endif // JUCE_BYTEORDER_H_INCLUDED
|
||||
|
||||
@@ -88,14 +88,14 @@ MemoryBlock& MemoryBlock::operator= (const MemoryBlock& other)
|
||||
|
||||
#if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
|
||||
MemoryBlock::MemoryBlock (MemoryBlock&& other) noexcept
|
||||
: data (static_cast <HeapBlock<char>&&> (other.data)),
|
||||
: data (static_cast<HeapBlock<char>&&> (other.data)),
|
||||
size (other.size)
|
||||
{
|
||||
}
|
||||
|
||||
MemoryBlock& MemoryBlock::operator= (MemoryBlock&& other) noexcept
|
||||
{
|
||||
data = static_cast <HeapBlock<char>&&> (other.data);
|
||||
data = static_cast<HeapBlock<char>&&> (other.data);
|
||||
size = other.size;
|
||||
return *this;
|
||||
}
|
||||
@@ -346,7 +346,7 @@ void MemoryBlock::loadFromHexString (StringRef hex)
|
||||
|
||||
if (c == 0)
|
||||
{
|
||||
setSize (static_cast <size_t> (dest - data));
|
||||
setSize (static_cast<size_t> (dest - data));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -208,7 +208,7 @@ private:
|
||||
The template parameter specifies the class of the object you want to point to - the easiest
|
||||
way to make a class reference-countable is to simply make it inherit from ReferenceCountedObject
|
||||
or SingleThreadedReferenceCountedObject, but if you need to, you can roll your own reference-countable
|
||||
class by implementing a set of mathods called incReferenceCount(), decReferenceCount(), and
|
||||
class by implementing a set of methods called incReferenceCount(), decReferenceCount(), and
|
||||
decReferenceCountWithoutDeleting(). See ReferenceCountedObject for examples of how these methods
|
||||
should behave.
|
||||
|
||||
|
||||
@@ -182,11 +182,11 @@ public:
|
||||
/** Swaps this object with that of another ScopedPointer.
|
||||
The two objects simply exchange their pointers.
|
||||
*/
|
||||
void swapWith (ScopedPointer <ObjectType>& other) noexcept
|
||||
void swapWith (ScopedPointer<ObjectType>& other) noexcept
|
||||
{
|
||||
// Two ScopedPointers should never be able to refer to the same object - if
|
||||
// this happens, you must have done something dodgy!
|
||||
jassert (object != other.object || this == other.getAddress());
|
||||
jassert (object != other.object || this == other.getAddress() || object == nullptr);
|
||||
|
||||
std::swap (object, other.object);
|
||||
}
|
||||
@@ -231,7 +231,7 @@ private:
|
||||
template <class ObjectType>
|
||||
bool operator== (const ScopedPointer<ObjectType>& pointer1, ObjectType* const pointer2) noexcept
|
||||
{
|
||||
return static_cast <ObjectType*> (pointer1) == pointer2;
|
||||
return static_cast<ObjectType*> (pointer1) == pointer2;
|
||||
}
|
||||
|
||||
/** Compares a ScopedPointer with another pointer.
|
||||
@@ -240,7 +240,7 @@ bool operator== (const ScopedPointer<ObjectType>& pointer1, ObjectType* const po
|
||||
template <class ObjectType>
|
||||
bool operator!= (const ScopedPointer<ObjectType>& pointer1, ObjectType* const pointer2) noexcept
|
||||
{
|
||||
return static_cast <ObjectType*> (pointer1) != pointer2;
|
||||
return static_cast<ObjectType*> (pointer1) != pointer2;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
||||
@@ -139,7 +139,7 @@ private:
|
||||
|
||||
static SharedObjectHolder& getSharedObjectHolder() noexcept
|
||||
{
|
||||
static char holder [sizeof (SharedObjectHolder)] = { 0 };
|
||||
static void* holder [(sizeof (SharedObjectHolder) + sizeof(void*) - 1) / sizeof(void*)] = { 0 };
|
||||
return *reinterpret_cast<SharedObjectHolder*> (holder);
|
||||
}
|
||||
|
||||
|
||||
@@ -158,7 +158,7 @@ public:
|
||||
public:
|
||||
Master() noexcept {}
|
||||
|
||||
~Master()
|
||||
~Master() noexcept
|
||||
{
|
||||
// You must remember to call clear() in your source object's destructor! See the notes
|
||||
// for the WeakReference class for an example of how to do this.
|
||||
@@ -187,7 +187,7 @@ public:
|
||||
to zero all the references to this object that may be out there. See the WeakReference
|
||||
class notes for an example of how to do this.
|
||||
*/
|
||||
void clear()
|
||||
void clear() noexcept
|
||||
{
|
||||
if (sharedPointer != nullptr)
|
||||
sharedPointer->clearPointer();
|
||||
|
||||
@@ -399,16 +399,21 @@ public final class JuceAppActivity extends Activity
|
||||
private native void handleKeyDown (long host, int keycode, int textchar);
|
||||
private native void handleKeyUp (long host, int keycode, int textchar);
|
||||
|
||||
public void showKeyboard (boolean shouldShow)
|
||||
public void showKeyboard (String type)
|
||||
{
|
||||
InputMethodManager imm = (InputMethodManager) getSystemService (Context.INPUT_METHOD_SERVICE);
|
||||
|
||||
if (imm != null)
|
||||
{
|
||||
if (shouldShow)
|
||||
imm.showSoftInput (this, InputMethodManager.SHOW_FORCED);
|
||||
if (type.length() > 0)
|
||||
{
|
||||
imm.showSoftInput (this, android.view.inputmethod.InputMethodManager.SHOW_IMPLICIT);
|
||||
imm.setInputMethod (getWindowToken(), type);
|
||||
}
|
||||
else
|
||||
{
|
||||
imm.hideSoftInputFromWindow (getWindowToken(), 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -271,26 +271,33 @@ public:
|
||||
|
||||
JNIEnv* attach() noexcept
|
||||
{
|
||||
if (JNIEnv* env = attachToCurrentThread())
|
||||
if (android.activity != nullptr)
|
||||
{
|
||||
SpinLock::ScopedLockType sl (addRemoveLock);
|
||||
return addEnv (env);
|
||||
if (JNIEnv* env = attachToCurrentThread())
|
||||
{
|
||||
SpinLock::ScopedLockType sl (addRemoveLock);
|
||||
return addEnv (env);
|
||||
}
|
||||
|
||||
jassertfalse;
|
||||
}
|
||||
|
||||
jassertfalse;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void detach() noexcept
|
||||
{
|
||||
jvm->DetachCurrentThread();
|
||||
if (android.activity != nullptr)
|
||||
{
|
||||
jvm->DetachCurrentThread();
|
||||
|
||||
const pthread_t thisThread = pthread_self();
|
||||
const pthread_t thisThread = pthread_self();
|
||||
|
||||
SpinLock::ScopedLockType sl (addRemoveLock);
|
||||
for (int i = 0; i < maxThreads; ++i)
|
||||
if (threads[i] == thisThread)
|
||||
threads[i] = 0;
|
||||
SpinLock::ScopedLockType sl (addRemoveLock);
|
||||
for (int i = 0; i < maxThreads; ++i)
|
||||
if (threads[i] == thisThread)
|
||||
threads[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
JNIEnv* getOrAttach() noexcept
|
||||
@@ -355,6 +362,12 @@ private:
|
||||
|
||||
extern ThreadLocalJNIEnvHolder threadLocalJNIEnvHolder;
|
||||
|
||||
struct AndroidThreadScope
|
||||
{
|
||||
AndroidThreadScope() { threadLocalJNIEnvHolder.attach(); }
|
||||
~AndroidThreadScope() { threadLocalJNIEnvHolder.detach(); }
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \
|
||||
METHOD (createNewView, "createNewView", "(ZJ)L" JUCE_ANDROID_ACTIVITY_CLASSPATH "$ComponentPeerView;") \
|
||||
|
||||
@@ -166,7 +166,7 @@ public:
|
||||
int numBytes = stream.callIntMethod (HTTPStream.read, javaArray, (jint) bytesToRead);
|
||||
|
||||
if (numBytes > 0)
|
||||
env->GetByteArrayRegion (javaArray, 0, numBytes, static_cast <jbyte*> (buffer));
|
||||
env->GetByteArrayRegion (javaArray, 0, numBytes, static_cast<jbyte*> (buffer));
|
||||
|
||||
env->DeleteLocalRef (javaArray);
|
||||
return numBytes;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user