Browse Source

Update juce_audio_basics

tags/1.9.4
falkTX 10 years ago
parent
commit
3e5c292a27
10 changed files with 637 additions and 324 deletions
  1. +1
    -1
      data/copy-juce-carla
  2. +362
    -86
      source/modules/juce_audio_basics/buffers/juce_FloatVectorOperations.cpp
  3. +5
    -2
      source/modules/juce_audio_basics/buffers/juce_FloatVectorOperations.h
  4. +5
    -0
      source/modules/juce_audio_basics/juce_audio_basics.cpp
  5. +195
    -195
      source/modules/juce_audio_basics/midi/juce_MidiMessage.cpp
  6. +8
    -9
      source/modules/juce_audio_basics/midi/juce_MidiMessage.h
  7. +1
    -4
      source/modules/juce_audio_basics/midi/juce_MidiMessageSequence.cpp
  8. +9
    -22
      source/modules/juce_audio_basics/midi/juce_MidiMessageSequence.h
  9. +20
    -0
      source/modules/juce_audio_basics/synthesisers/juce_Synthesiser.cpp
  10. +31
    -5
      source/modules/juce_audio_basics/synthesisers/juce_Synthesiser.h

+ 1
- 1
data/copy-juce-carla View File

@@ -6,7 +6,7 @@ JUCE_MODULES_DIR="/home/falktx/Personal/FOSS/GIT/DISTRHO/libs/juce/source/module
CARLA_MODULES_DIR="/home/falktx/Personal/FOSS/GIT/Carla/source/modules"

# MODULES=("juce_audio_basics juce_audio_devices juce_audio_formats juce_audio_processors juce_core juce_data_structures juce_events juce_graphics juce_gui_basics")
MODULES=("juce_core")
MODULES=("juce_audio_basics")

for M in $MODULES; do
echo $M;


+ 362
- 86
source/modules/juce_audio_basics/buffers/juce_FloatVectorOperations.cpp View File

@@ -22,10 +22,13 @@
==============================================================================
*/
#if JUCE_USE_SSE_INTRINSICS
namespace FloatVectorHelpers
{
#define JUCE_INCREMENT_SRC_DEST dest += 4; src += 4;
#define JUCE_INCREMENT_DEST dest += 4;
#if JUCE_USE_SSE_INTRINSICS
static bool sse2Present = false;
static bool isSSE2Available() noexcept
@@ -44,7 +47,6 @@ namespace FloatVectorHelpers
static inline float findMinimumOrMaximum (const float* src, int num, const bool isMinimum) noexcept
{
#if JUCE_USE_SSE_INTRINSICS
const int numLongOps = num / 4;
if (numLongOps > 1 && FloatVectorHelpers::isSSE2Available())
@@ -90,66 +92,142 @@ namespace FloatVectorHelpers
return localVal;
}
#endif
return isMinimum ? juce::findMinimum (src, num)
: juce::findMaximum (src, num);
}
}
#define JUCE_BEGIN_SSE_OP \
if (FloatVectorHelpers::isSSE2Available()) \
{ \
#define JUCE_BEGIN_SSE_OP \
if (FloatVectorHelpers::isSSE2Available()) \
{ \
const int numLongOps = num / 4;
#define JUCE_FINISH_SSE_OP(normalOp) \
num &= 3; \
if (num == 0) return; \
} \
for (int i = 0; i < num; ++i) normalOp;
#define JUCE_SSE_LOOP(sseOp, srcLoad, dstLoad, dstStore, locals, increment) \
for (int i = 0; i < numLongOps; ++i) \
{ \
locals (srcLoad, dstLoad); \
dstStore (dest, sseOp); \
increment; \
}
#define JUCE_LOAD_NONE(srcLoad, dstLoad)
#define JUCE_LOAD_DEST(srcLoad, dstLoad) const __m128 d = dstLoad (dest);
#define JUCE_LOAD_SRC(srcLoad, dstLoad) const __m128 s = srcLoad (src);
#define JUCE_LOAD_SRC_DEST(srcLoad, dstLoad) const __m128 d = dstLoad (dest); const __m128 s = srcLoad (src);
#define JUCE_PERFORM_SSE_OP_DEST(normalOp, sseOp, locals) \
JUCE_BEGIN_SSE_OP \
if (FloatVectorHelpers::isAligned (dest)) JUCE_SSE_LOOP (sseOp, dummy, _mm_load_ps, _mm_store_ps, locals, JUCE_INCREMENT_DEST) \
else JUCE_SSE_LOOP (sseOp, dummy, _mm_loadu_ps, _mm_storeu_ps, locals, JUCE_INCREMENT_DEST) \
JUCE_FINISH_SSE_OP (normalOp)
#define JUCE_PERFORM_SSE_OP_SRC_DEST(normalOp, sseOp, locals, increment) \
JUCE_BEGIN_SSE_OP \
if (FloatVectorHelpers::isAligned (dest)) \
{ \
if (FloatVectorHelpers::isAligned (src)) JUCE_SSE_LOOP (sseOp, _mm_load_ps, _mm_load_ps, _mm_store_ps, locals, increment) \
else JUCE_SSE_LOOP (sseOp, _mm_loadu_ps, _mm_load_ps, _mm_store_ps, locals, increment) \
}\
else \
{ \
if (FloatVectorHelpers::isAligned (src)) JUCE_SSE_LOOP (sseOp, _mm_load_ps, _mm_loadu_ps, _mm_storeu_ps, locals, increment) \
else JUCE_SSE_LOOP (sseOp, _mm_loadu_ps, _mm_loadu_ps, _mm_storeu_ps, locals, increment) \
} \
JUCE_FINISH_SSE_OP (normalOp)
//==============================================================================
#elif JUCE_USE_ARM_NEON
static inline float findMinimumOrMaximum (const float* src, int num, const bool isMinimum) noexcept
{
const int numLongOps = num / 4;
if (numLongOps > 1)
{
float32x4_t val;
#define JUCE_MINIMUMMAXIMUM_NEON_LOOP(loadOp, minMaxOp) \
val = loadOp (src); \
src += 4; \
for (int i = 1; i < numLongOps; ++i) \
{ \
const float32x4_t s = loadOp (src); \
val = minMaxOp (val, s); \
src += 4; \
}
if (isMinimum) { JUCE_MINIMUMMAXIMUM_NEON_LOOP (vld1q_f32, vminq_f32) }
else { JUCE_MINIMUMMAXIMUM_NEON_LOOP (vld1q_f32, vmaxq_f32) }
float localVal;
{
float vals[4];
vst1q_f32 (vals, val);
localVal = isMinimum ? jmin (vals[0], vals[1], vals[2], vals[3])
: jmax (vals[0], vals[1], vals[2], vals[3]);
}
num &= 3;
for (int i = 0; i < num; ++i)
localVal = isMinimum ? jmin (localVal, src[i])
: jmax (localVal, src[i]);
return localVal;
}
return isMinimum ? juce::findMinimum (src, num)
: juce::findMaximum (src, num);
}
#define JUCE_BEGIN_NEON_OP \
const int numLongOps = num / 4;
#define JUCE_FINISH_SSE_OP(normalOp) \
#define JUCE_FINISH_NEON_OP(normalOp) \
num &= 3; \
if (num == 0) return; \
} \
for (int i = 0; i < num; ++i) normalOp;
#define JUCE_SSE_LOOP(sseOp, srcLoad, dstLoad, dstStore, locals, increment) \
for (int i = 0; i < numLongOps; ++i) \
{ \
locals (srcLoad, dstLoad); \
dstStore (dest, sseOp); \
increment; \
}
for (int i = 0; i < num; ++i) normalOp;
#define JUCE_NEON_LOOP(neonOp, srcLoad, dstLoad, dstStore, locals, increment) \
for (int i = 0; i < numLongOps; ++i) \
{ \
locals (srcLoad, dstLoad); \
dstStore (dest, neonOp); \
increment; \
}
#define JUCE_INCREMENT_SRC_DEST dest += 4; src += 4;
#define JUCE_INCREMENT_DEST dest += 4;
#define JUCE_LOAD_NONE(srcLoad, dstLoad)
#define JUCE_LOAD_DEST(srcLoad, dstLoad) const __m128 d = dstLoad (dest);
#define JUCE_LOAD_SRC(srcLoad, dstLoad) const __m128 s = srcLoad (src);
#define JUCE_LOAD_SRC_DEST(srcLoad, dstLoad) const __m128 d = dstLoad (dest); const __m128 s = srcLoad (src);
#define JUCE_PERFORM_SSE_OP_DEST(normalOp, sseOp, locals) \
JUCE_BEGIN_SSE_OP \
if (FloatVectorHelpers::isAligned (dest)) JUCE_SSE_LOOP (sseOp, dummy, _mm_load_ps, _mm_store_ps, locals, JUCE_INCREMENT_DEST) \
else JUCE_SSE_LOOP (sseOp, dummy, _mm_loadu_ps, _mm_storeu_ps, locals, JUCE_INCREMENT_DEST) \
JUCE_FINISH_SSE_OP (normalOp)
#define JUCE_PERFORM_SSE_OP_SRC_DEST(normalOp, sseOp, locals, increment) \
JUCE_BEGIN_SSE_OP \
if (FloatVectorHelpers::isAligned (dest)) \
{ \
if (FloatVectorHelpers::isAligned (src)) JUCE_SSE_LOOP (sseOp, _mm_load_ps, _mm_load_ps, _mm_store_ps, locals, increment) \
else JUCE_SSE_LOOP (sseOp, _mm_loadu_ps, _mm_load_ps, _mm_store_ps, locals, increment) \
}\
else \
{ \
if (FloatVectorHelpers::isAligned (src)) JUCE_SSE_LOOP (sseOp, _mm_load_ps, _mm_loadu_ps, _mm_storeu_ps, locals, increment) \
else JUCE_SSE_LOOP (sseOp, _mm_loadu_ps, _mm_loadu_ps, _mm_storeu_ps, locals, increment) \
} \
JUCE_FINISH_SSE_OP (normalOp)
#else
#define JUCE_PERFORM_SSE_OP_DEST(normalOp, unused1, unused2) for (int i = 0; i < num; ++i) normalOp;
#define JUCE_PERFORM_SSE_OP_SRC_DEST(normalOp, sseOp, locals, increment) for (int i = 0; i < num; ++i) normalOp;
#endif
#define JUCE_LOAD_NONE(srcLoad, dstLoad)
#define JUCE_LOAD_DEST(srcLoad, dstLoad) const float32x4_t d = dstLoad (dest);
#define JUCE_LOAD_SRC(srcLoad, dstLoad) const float32x4_t s = srcLoad (src);
#define JUCE_LOAD_SRC_DEST(srcLoad, dstLoad) const float32x4_t d = dstLoad (dest); const float32x4_t s = srcLoad (src);
#define JUCE_PERFORM_NEON_OP_DEST(normalOp, neonOp, locals) \
JUCE_BEGIN_NEON_OP \
JUCE_NEON_LOOP (neonOp, dummy, vld1q_f32, vst1q_f32, locals, JUCE_INCREMENT_DEST) \
JUCE_FINISH_NEON_OP (normalOp)
#define JUCE_PERFORM_NEON_OP_SRC_DEST(normalOp, neonOp, locals) \
JUCE_BEGIN_NEON_OP \
JUCE_NEON_LOOP (neonOp, vld1q_f32, vld1q_f32, vst1q_f32, locals, JUCE_INCREMENT_SRC_DEST) \
JUCE_FINISH_NEON_OP (normalOp)
//==============================================================================
#else
#define JUCE_PERFORM_SSE_OP_DEST(normalOp, unused1, unused2) for (int i = 0; i < num; ++i) normalOp;
#define JUCE_PERFORM_SSE_OP_SRC_DEST(normalOp, sseOp, locals, increment) for (int i = 0; i < num; ++i) normalOp;
#endif
}
//==============================================================================
void JUCE_CALLTYPE FloatVectorOperations::clear (float* dest, int num) noexcept
{
#if JUCE_USE_VDSP_FRAMEWORK
@@ -163,11 +241,13 @@ void JUCE_CALLTYPE FloatVectorOperations::fill (float* dest, float valueToFill,
{
#if JUCE_USE_VDSP_FRAMEWORK
vDSP_vfill (&valueToFill, dest, 1, (size_t) num);
#elif JUCE_USE_ARM_NEON
const float32x4_t val = vld1q_dup_f32 (&valueToFill);
JUCE_PERFORM_NEON_OP_DEST (dest[i] = valueToFill, val, JUCE_LOAD_NONE)
#else
#if JUCE_USE_SSE_INTRINSICS
const __m128 val = _mm_load1_ps (&valueToFill);
#endif
JUCE_PERFORM_SSE_OP_DEST (dest[i] = valueToFill, val, JUCE_LOAD_NONE)
#endif
}
@@ -181,58 +261,78 @@ void JUCE_CALLTYPE FloatVectorOperations::copyWithMultiply (float* dest, const f
{
#if JUCE_USE_VDSP_FRAMEWORK
vDSP_vsmul (src, 1, &multiplier, dest, 1, num);
#elif JUCE_USE_ARM_NEON
JUCE_PERFORM_NEON_OP_SRC_DEST (dest[i] += src[i], vmulq_n_f32(s, multiplier), JUCE_LOAD_SRC)
#else
#if JUCE_USE_SSE_INTRINSICS
const __m128 mult = _mm_load1_ps (&multiplier);
#endif
JUCE_PERFORM_SSE_OP_SRC_DEST (dest[i] = src[i] * multiplier,
_mm_mul_ps (mult, s),
JUCE_PERFORM_SSE_OP_SRC_DEST (dest[i] = src[i] * multiplier, _mm_mul_ps (mult, s),
JUCE_LOAD_SRC, JUCE_INCREMENT_SRC_DEST)
#endif
}
void JUCE_CALLTYPE FloatVectorOperations::add (float* dest, float amount, int num) noexcept
{
#if JUCE_USE_ARM_NEON
const float32x4_t amountToAdd = vld1q_dup_f32(&amount);
JUCE_PERFORM_NEON_OP_DEST (dest[i] += amount, vaddq_f32 (d, amountToAdd), JUCE_LOAD_DEST)
#else
#if JUCE_USE_SSE_INTRINSICS
const __m128 amountToAdd = _mm_load1_ps (&amount);
#endif
JUCE_PERFORM_SSE_OP_DEST (dest[i] += amount, _mm_add_ps (d, amountToAdd), JUCE_LOAD_DEST)
#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);
#elif JUCE_USE_ARM_NEON
JUCE_PERFORM_NEON_OP_SRC_DEST (dest[i] += src[i], vaddq_f32 (d, s), JUCE_LOAD_SRC_DEST)
#else
JUCE_PERFORM_SSE_OP_SRC_DEST (dest[i] += src[i],
_mm_add_ps (d, s),
JUCE_LOAD_SRC_DEST, JUCE_INCREMENT_SRC_DEST)
JUCE_PERFORM_SSE_OP_SRC_DEST (dest[i] += src[i], _mm_add_ps (d, s), JUCE_LOAD_SRC_DEST, JUCE_INCREMENT_SRC_DEST)
#endif
}
void JUCE_CALLTYPE FloatVectorOperations::add (float* dest, float amount, int num) noexcept
void JUCE_CALLTYPE FloatVectorOperations::subtract (float* dest, const float* src, int num) noexcept
{
#if JUCE_USE_SSE_INTRINSICS
const __m128 amountToAdd = _mm_load1_ps (&amount);
#if JUCE_USE_VDSP_FRAMEWORK
vDSP_vsub (src, 1, dest, 1, dest, 1, num);
#elif JUCE_USE_ARM_NEON
JUCE_PERFORM_NEON_OP_SRC_DEST (dest[i] -= src[i], vsubq_f32 (d, s), JUCE_LOAD_SRC_DEST)
#else
JUCE_PERFORM_SSE_OP_SRC_DEST (dest[i] -= src[i], _mm_sub_ps (d, s), JUCE_LOAD_SRC_DEST, JUCE_INCREMENT_SRC_DEST)
#endif
JUCE_PERFORM_SSE_OP_DEST (dest[i] += amount,
_mm_add_ps (d, amountToAdd),
JUCE_LOAD_DEST)
}
void JUCE_CALLTYPE FloatVectorOperations::addWithMultiply (float* dest, const float* src, float multiplier, int num) noexcept
{
#if JUCE_USE_SSE_INTRINSICS
const __m128 mult = _mm_load1_ps (&multiplier);
#if JUCE_USE_ARM_NEON
JUCE_PERFORM_NEON_OP_SRC_DEST (dest[i] += src[i] * multiplier,
vmlaq_n_f32 (d, s, multiplier),
JUCE_LOAD_SRC_DEST)
#else
#if JUCE_USE_SSE_INTRINSICS
const __m128 mult = _mm_load1_ps (&multiplier);
#endif
JUCE_PERFORM_SSE_OP_SRC_DEST (dest[i] += src[i] * multiplier,
_mm_add_ps (d, _mm_mul_ps (mult, s)),
JUCE_LOAD_SRC_DEST, JUCE_INCREMENT_SRC_DEST)
#endif
JUCE_PERFORM_SSE_OP_SRC_DEST (dest[i] += src[i] * multiplier,
_mm_add_ps (d, _mm_mul_ps (mult, s)),
JUCE_LOAD_SRC_DEST, JUCE_INCREMENT_SRC_DEST)
}
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);
#elif JUCE_USE_ARM_NEON
JUCE_PERFORM_NEON_OP_SRC_DEST (dest[i] *= src[i], vmulq_f32 (d, s), JUCE_LOAD_SRC_DEST)
#else
JUCE_PERFORM_SSE_OP_SRC_DEST (dest[i] *= src[i],
_mm_mul_ps (d, s),
JUCE_LOAD_SRC_DEST, JUCE_INCREMENT_SRC_DEST)
JUCE_PERFORM_SSE_OP_SRC_DEST (dest[i] *= src[i], _mm_mul_ps (d, s), JUCE_LOAD_SRC_DEST, JUCE_INCREMENT_SRC_DEST)
#endif
}
@@ -240,14 +340,13 @@ void JUCE_CALLTYPE FloatVectorOperations::multiply (float* dest, float multiplie
{
#if JUCE_USE_VDSP_FRAMEWORK
vDSP_vsmul (dest, 1, &multiplier, dest, 1, num);
#elif JUCE_USE_ARM_NEON
JUCE_PERFORM_NEON_OP_DEST (dest[i] *= multiplier, vmulq_n_f32 (d, multiplier), JUCE_LOAD_DEST)
#else
#if JUCE_USE_SSE_INTRINSICS
const __m128 mult = _mm_load1_ps (&multiplier);
#endif
JUCE_PERFORM_SSE_OP_DEST (dest[i] *= multiplier,
_mm_mul_ps (d, mult),
JUCE_LOAD_DEST)
JUCE_PERFORM_SSE_OP_DEST (dest[i] *= multiplier, _mm_mul_ps (d, mult), JUCE_LOAD_DEST)
#endif
}
@@ -262,13 +361,19 @@ void FloatVectorOperations::negate (float* dest, const float* src, int num) noex
void JUCE_CALLTYPE FloatVectorOperations::convertFixedToFloat (float* dest, const int* src, float multiplier, int num) noexcept
{
#if JUCE_USE_SSE_INTRINSICS
const __m128 mult = _mm_load1_ps (&multiplier);
#endif
#if JUCE_USE_ARM_NEON
JUCE_PERFORM_NEON_OP_SRC_DEST (dest[i] = src[i] * multiplier,
vmulq_n_f32 (vcvtq_f32_s32 (vld1q_s32 (src)), multiplier),
JUCE_LOAD_NONE)
#else
#if JUCE_USE_SSE_INTRINSICS
const __m128 mult = _mm_load1_ps (&multiplier);
#endif
JUCE_PERFORM_SSE_OP_SRC_DEST (dest[i] = src[i] * multiplier,
_mm_mul_ps (mult, _mm_cvtepi32_ps (_mm_loadu_si128 ((const __m128i*) src))),
JUCE_LOAD_NONE, JUCE_INCREMENT_SRC_DEST)
JUCE_PERFORM_SSE_OP_SRC_DEST (dest[i] = src[i] * multiplier,
_mm_mul_ps (mult, _mm_cvtepi32_ps (_mm_loadu_si128 ((const __m128i*) src))),
JUCE_LOAD_NONE, JUCE_INCREMENT_SRC_DEST)
#endif
}
void JUCE_CALLTYPE FloatVectorOperations::findMinAndMax (const float* src, int num, float& minResult, float& maxResult) noexcept
@@ -315,6 +420,51 @@ void JUCE_CALLTYPE FloatVectorOperations::findMinAndMax (const float* src, int n
localMax = jmax (localMax, s);
}
minResult = localMin;
maxResult = localMax;
return;
}
#elif JUCE_USE_ARM_NEON
const int numLongOps = num / 4;
if (numLongOps > 1)
{
float32x4_t mn, mx;
#define JUCE_MINMAX_NEON_LOOP(loadOp) \
mn = loadOp (src); \
mx = mn; \
src += 4; \
for (int i = 1; i < numLongOps; ++i) \
{ \
const float32x4_t s = loadOp (src); \
mn = vminq_f32 (mn, s); \
mx = vmaxq_f32 (mx, s); \
src += 4; \
}
JUCE_MINMAX_NEON_LOOP (vld1q_f32);
float localMin, localMax;
{
float mns[4], mxs[4];
vst1q_f32 (mns, mn);
vst1q_f32 (mxs, mx);
localMin = jmin (mns[0], mns[1], mns[2], mns[3]);
localMax = jmax (mxs[0], mxs[1], mxs[2], mxs[3]);
}
num &= 3;
for (int i = 0; i < num; ++i)
{
const float s = src[i];
localMin = jmin (localMin, s);
localMax = jmax (localMax, s);
}
minResult = localMin;
maxResult = localMax;
return;
@@ -326,7 +476,7 @@ void JUCE_CALLTYPE FloatVectorOperations::findMinAndMax (const float* src, int n
float JUCE_CALLTYPE FloatVectorOperations::findMinimum (const float* src, int num) noexcept
{
#if JUCE_USE_SSE_INTRINSICS
#if JUCE_USE_SSE_INTRINSICS || JUCE_USE_ARM_NEON
return FloatVectorHelpers::findMinimumOrMaximum (src, num, true);
#else
return juce::findMinimum (src, num);
@@ -335,7 +485,7 @@ float JUCE_CALLTYPE FloatVectorOperations::findMinimum (const float* src, int nu
float JUCE_CALLTYPE FloatVectorOperations::findMaximum (const float* src, int num) noexcept
{
#if JUCE_USE_SSE_INTRINSICS
#if JUCE_USE_SSE_INTRINSICS || JUCE_USE_ARM_NEON
return FloatVectorHelpers::findMinimumOrMaximum (src, num, false);
#else
return juce::findMaximum (src, num);
@@ -350,3 +500,129 @@ void JUCE_CALLTYPE FloatVectorOperations::enableFlushToZeroMode (bool shouldEnab
#endif
(void) shouldEnable;
}
//==============================================================================
//==============================================================================
#if JUCE_UNIT_TESTS
class FloatVectorOperationsTests : public UnitTest
{
public:
FloatVectorOperationsTests() : UnitTest ("FloatVectorOperations") {}
void runTest()
{
beginTest ("FloatVectorOperations");
for (int i = 100; --i >= 0;)
{
const int num = getRandom().nextInt (500) + 1;
HeapBlock<float> buffer1 (num + 16), buffer2 (num + 16);
HeapBlock<int> buffer3 (num + 16);
#if JUCE_ARM
float* const data1 = buffer1;
float* const data2 = buffer2;
int* const int1 = buffer3;
#else
float* const data1 = addBytesToPointer (buffer1.getData(), getRandom().nextInt (16));
float* const data2 = addBytesToPointer (buffer2.getData(), getRandom().nextInt (16));
int* const int1 = addBytesToPointer (buffer3.getData(), getRandom().nextInt (16));
#endif
fillRandomly (data1, num);
fillRandomly (data2, num);
float mn1, mx1, mn2, mx2;
FloatVectorOperations::findMinAndMax (data1, num, mn1, mx1);
juce::findMinAndMax (data1, num, mn2, mx2);
expect (mn1 == mn2);
expect (mx1 == mx2);
expect (FloatVectorOperations::findMinimum (data1, num) == juce::findMinimum (data1, num));
expect (FloatVectorOperations::findMaximum (data1, num) == juce::findMaximum (data1, num));
expect (FloatVectorOperations::findMinimum (data2, num) == juce::findMinimum (data2, num));
expect (FloatVectorOperations::findMaximum (data2, num) == juce::findMaximum (data2, num));
FloatVectorOperations::clear (data1, num);
expect (areAllValuesEqual (data1, num, 0));
FloatVectorOperations::fill (data1, 2.0f, num);
expect (areAllValuesEqual (data1, num, 2.0f));
FloatVectorOperations::add (data1, 2.0f, num);
expect (areAllValuesEqual (data1, num, 4.0f));
FloatVectorOperations::copy (data2, data1, num);
expect (areAllValuesEqual (data2, num, 4.0f));
FloatVectorOperations::add (data2, data1, num);
expect (areAllValuesEqual (data2, num, 8.0f));
FloatVectorOperations::copyWithMultiply (data2, data1, 4.0f, num);
expect (areAllValuesEqual (data2, num, 16.0f));
FloatVectorOperations::addWithMultiply (data2, data1, 4.0f, num);
expect (areAllValuesEqual (data2, num, 32.0f));
FloatVectorOperations::multiply (data1, 2.0f, num);
expect (areAllValuesEqual (data1, num, 8.0f));
FloatVectorOperations::multiply (data1, data2, num);
expect (areAllValuesEqual (data1, num, 256.0f));
FloatVectorOperations::negate (data2, data1, num);
expect (areAllValuesEqual (data2, num, -256.0f));
FloatVectorOperations::subtract (data1, data2, num);
expect (areAllValuesEqual (data1, num, 512.0f));
fillRandomly (int1, num);
FloatVectorOperations::convertFixedToFloat (data1, int1, 2.0f, num);
convertFixed (data2, int1, 2.0f, num);
expect (buffersMatch (data1, data2, num));
}
}
void fillRandomly (float* d, int num)
{
while (--num >= 0)
*d++ = getRandom().nextFloat() * 1000.0f;
}
void fillRandomly (int* d, int num)
{
while (--num >= 0)
*d++ = getRandom().nextInt();
}
static void convertFixed (float* d, const int* s, float multiplier, int num)
{
while (--num >= 0)
*d++ = *s++ * multiplier;
}
static bool areAllValuesEqual (const float* d, int num, float target)
{
while (--num >= 0)
if (*d++ != target)
return false;
return true;
}
static bool buffersMatch (const float* d1, const float* d2, int num)
{
while (--num >= 0)
if (std::abs (*d1++ - *d2++) > std::numeric_limits<float>::epsilon())
return false;
return true;
}
};
static FloatVectorOperationsTests vectorOpTests;
#endif

+ 5
- 2
source/modules/juce_audio_basics/buffers/juce_FloatVectorOperations.h View File

@@ -47,11 +47,14 @@ public:
/** Copies a vector of floats, multiplying each value by a given multiplier */
static void JUCE_CALLTYPE copyWithMultiply (float* dest, const float* src, float multiplier, int numValues) noexcept;
/** Adds a fixed value to the destination values. */
static void JUCE_CALLTYPE add (float* dest, float 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 a fixed value to the destination values. */
static void JUCE_CALLTYPE add (float* dest, float amount, int numValues) noexcept;
/** Subtracts the source values from the destination values. */
static void JUCE_CALLTYPE subtract (float* dest, const float* src, int numValues) 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;


+ 5
- 0
source/modules/juce_audio_basics/juce_audio_basics.cpp View File

@@ -58,6 +58,11 @@
#undef JUCE_USE_VDSP_FRAMEWORK
#endif
#if __ARM_NEON__ && ! (JUCE_USE_VDSP_FRAMEWORK || defined (JUCE_USE_ARM_NEON))
#define JUCE_USE_ARM_NEON 1
#include <arm_neon.h>
#endif
namespace juce
{


+ 195
- 195
source/modules/juce_audio_basics/midi/juce_MidiMessage.cpp View File

@@ -39,8 +39,7 @@ namespace MidiHelpers
int MidiMessage::readVariableLengthVal (const uint8* data, int& numBytesUsed) noexcept
{
numBytesUsed = 0;
int v = 0;
int i;
int v = 0, i;
do
{
@@ -76,28 +75,9 @@ int MidiMessage::getMessageLengthFromFirstByte (const uint8 firstByte) noexcept
return messageLengths [firstByte & 0x7f];
}
//==============================================================================
inline void MidiMessage::setToUseInternalData() noexcept
{
data = static_cast <uint8*> (preallocatedData.asBytes);
}
inline bool MidiMessage::usesAllocatedData() const noexcept
{
return data != static_cast <const uint8*> (preallocatedData.asBytes);
}
inline void MidiMessage::freeData() noexcept
{
if (usesAllocatedData())
delete[] data;
}
//==============================================================================
MidiMessage::MidiMessage() noexcept
: timeStamp (0),
data (static_cast<uint8*> (preallocatedData.asBytes)),
size (2)
: timeStamp (0), size (2)
{
preallocatedData.asBytes[0] = 0xf0;
preallocatedData.asBytes[1] = 0xf7;
@@ -108,22 +88,14 @@ MidiMessage::MidiMessage (const void* const d, const int dataSize, const double
size (dataSize)
{
jassert (dataSize > 0);
if (dataSize <= 4)
setToUseInternalData();
else
data = new uint8 [dataSize];
memcpy (data, d, (size_t) dataSize);
memcpy (allocateSpace (dataSize), d, (size_t) dataSize);
// check that the length matches the data..
jassert (size > 3 || data[0] >= 0xf0 || getMessageLengthFromFirstByte (data[0]) == size);
jassert (size > 3 || *(uint8*)d >= 0xf0 || getMessageLengthFromFirstByte (*(uint8*)d) == size);
}
MidiMessage::MidiMessage (const int byte1, const double t) noexcept
: timeStamp (t),
data (static_cast<uint8*> (preallocatedData.asBytes)),
size (1)
: timeStamp (t), size (1)
{
preallocatedData.asBytes[0] = (uint8) byte1;
@@ -132,9 +104,7 @@ MidiMessage::MidiMessage (const int byte1, const double t) noexcept
}
MidiMessage::MidiMessage (const int byte1, const int byte2, const double t) noexcept
: timeStamp (t),
data (static_cast<uint8*> (preallocatedData.asBytes)),
size (2)
: timeStamp (t), size (2)
{
preallocatedData.asBytes[0] = (uint8) byte1;
preallocatedData.asBytes[1] = (uint8) byte2;
@@ -144,9 +114,7 @@ MidiMessage::MidiMessage (const int byte1, const int byte2, const double t) noex
}
MidiMessage::MidiMessage (const int byte1, const int byte2, const int byte3, const double t) noexcept
: timeStamp (t),
data (static_cast<uint8*> (preallocatedData.asBytes)),
size (3)
: timeStamp (t), size (3)
{
preallocatedData.asBytes[0] = (uint8) byte1;
preallocatedData.asBytes[1] = (uint8) byte2;
@@ -157,42 +125,37 @@ MidiMessage::MidiMessage (const int byte1, const int byte2, const int byte3, con
}
MidiMessage::MidiMessage (const MidiMessage& other)
: timeStamp (other.timeStamp),
size (other.size)
: timeStamp (other.timeStamp), size (other.size)
{
if (other.usesAllocatedData())
if (other.allocatedData != nullptr)
{
data = new uint8 [size];
memcpy (data, other.data, (size_t) size);
allocatedData.malloc (size);
memcpy (allocatedData, other.allocatedData, (size_t) size);
}
else
{
setToUseInternalData();
preallocatedData.asInt32 = other.preallocatedData.asInt32;
}
}
MidiMessage::MidiMessage (const MidiMessage& other, const double newTimeStamp)
: timeStamp (newTimeStamp),
size (other.size)
: timeStamp (newTimeStamp), size (other.size)
{
if (other.usesAllocatedData())
if (other.allocatedData != nullptr)
{
data = new uint8 [size];
memcpy (data, other.data, (size_t) size);
allocatedData.malloc (size);
memcpy (allocatedData, other.allocatedData, (size_t) size);
}
else
{
setToUseInternalData();
preallocatedData.asInt32 = other.preallocatedData.asInt32;
}
}
MidiMessage::MidiMessage (const void* src_, int sz, int& numBytesUsed, const uint8 lastStatusByte, double t)
: timeStamp (t),
data (static_cast<uint8*> (preallocatedData.asBytes))
MidiMessage::MidiMessage (const void* srcData, int sz, int& numBytesUsed, const uint8 lastStatusByte, double t)
: timeStamp (t)
{
const uint8* src = static_cast <const uint8*> (src_);
const uint8* src = static_cast <const uint8*> (srcData);
unsigned int byte = (unsigned int) *src;
if (byte < 0x80)
@@ -229,11 +192,8 @@ MidiMessage::MidiMessage (const void* src_, int sz, int& numBytesUsed, const uin
break; // bytes, assume it's the end of the sysex
++numVariableLengthSysexBytes;
++d;
continue;
}
if (! haveReadAllLengthBytes)
else if (! haveReadAllLengthBytes)
{
haveReadAllLengthBytes = true;
++numVariableLengthSysexBytes;
@@ -242,11 +202,14 @@ MidiMessage::MidiMessage (const void* src_, int sz, int& numBytesUsed, const uin
++d;
}
src += numVariableLengthSysexBytes;
size = 1 + (int) (d - src);
data = new uint8 [size - numVariableLengthSysexBytes];
*data = (uint8) byte;
memcpy (data + 1, src + numVariableLengthSysexBytes, (size_t) (size - numVariableLengthSysexBytes - 1));
uint8* dest = allocateSpace (size);
*dest = (uint8) byte;
memcpy (dest + 1, src, (size_t) (size - 1));
numBytesUsed += numVariableLengthSysexBytes; // (these aren't counted in the size)
}
else if (byte == 0xff)
{
@@ -254,22 +217,22 @@ MidiMessage::MidiMessage (const void* src_, int sz, int& numBytesUsed, const uin
const int bytesLeft = readVariableLengthVal (src + 1, n);
size = jmin (sz + 1, n + 2 + bytesLeft);
data = new uint8 [size];
*data = (uint8) byte;
memcpy (data + 1, src, (size_t) size - 1);
uint8* dest = allocateSpace (size);
*dest = (uint8) byte;
memcpy (dest + 1, src, (size_t) size - 1);
}
else
{
preallocatedData.asInt32 = 0;
size = getMessageLengthFromFirstByte ((uint8) byte);
data[0] = (uint8) byte;
preallocatedData.asBytes[0] = (uint8) byte;
if (size > 1)
{
data[1] = src[0];
preallocatedData.asBytes[1] = src[0];
if (size > 2)
data[2] = src[1];
preallocatedData.asBytes[2] = src[1];
}
}
@@ -289,16 +252,14 @@ MidiMessage& MidiMessage::operator= (const MidiMessage& other)
timeStamp = other.timeStamp;
size = other.size;
freeData();
if (other.usesAllocatedData())
if (other.allocatedData != nullptr)
{
data = new uint8 [size];
memcpy (data, other.data, (size_t) size);
allocatedData.malloc (size);
memcpy (allocatedData, other.allocatedData, (size_t) size);
}
else
{
setToUseInternalData();
allocatedData.free();
preallocatedData.asInt32 = other.preallocatedData.asInt32;
}
}
@@ -308,19 +269,12 @@ MidiMessage& MidiMessage::operator= (const MidiMessage& other)
#if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
MidiMessage::MidiMessage (MidiMessage&& other) noexcept
: timeStamp (other.timeStamp),
size (other.size)
: timeStamp (other.timeStamp), size (other.size)
{
if (other.usesAllocatedData())
{
data = other.data;
other.setToUseInternalData();
}
if (other.allocatedData != nullptr)
allocatedData.swapWith (other.allocatedData);
else
{
setToUseInternalData();
preallocatedData.asInt32 = other.preallocatedData.asInt32;
}
}
MidiMessage& MidiMessage::operator= (MidiMessage&& other) noexcept
@@ -329,31 +283,30 @@ MidiMessage& MidiMessage::operator= (MidiMessage&& other) noexcept
timeStamp = other.timeStamp;
size = other.size;
freeData();
if (other.usesAllocatedData())
{
data = other.data;
other.setToUseInternalData();
}
else
{
setToUseInternalData();
preallocatedData.asInt32 = other.preallocatedData.asInt32;
}
allocatedData.swapWith (other.allocatedData);
preallocatedData.asInt32 = other.preallocatedData.asInt32;
return *this;
}
#endif
MidiMessage::~MidiMessage()
MidiMessage::~MidiMessage() {}
uint8* MidiMessage::allocateSpace (int bytes)
{
freeData();
if (bytes > 4)
{
allocatedData.malloc (bytes);
return allocatedData;
}
return preallocatedData.asBytes;
}
int MidiMessage::getChannel() const noexcept
{
const uint8* const data = getRawData();
if ((data[0] & 0xf0) != 0xf0)
return (data[0] & 0xf) + 1;
@@ -364,6 +317,8 @@ bool MidiMessage::isForChannel (const int channel) const noexcept
{
jassert (channel > 0 && channel <= 16); // valid channels are numbered 1 to 16
const uint8* const data = getRawData();
return ((data[0] & 0xf) == channel - 1)
&& ((data[0] & 0xf0) != 0xf0);
}
@@ -372,6 +327,8 @@ void MidiMessage::setChannel (const int channel) noexcept
{
jassert (channel > 0 && channel <= 16); // valid channels are numbered 1 to 16
uint8* const data = getData();
if ((data[0] & 0xf0) != (uint8) 0xf0)
data[0] = (uint8) ((data[0] & (uint8) 0xf0)
| (uint8)(channel - 1));
@@ -379,37 +336,43 @@ void MidiMessage::setChannel (const int channel) noexcept
bool MidiMessage::isNoteOn (const bool returnTrueForVelocity0) const noexcept
{
const uint8* const data = getRawData();
return ((data[0] & 0xf0) == 0x90)
&& (returnTrueForVelocity0 || data[2] != 0);
}
bool MidiMessage::isNoteOff (const bool returnTrueForNoteOnVelocity0) const noexcept
{
const uint8* const data = getRawData();
return ((data[0] & 0xf0) == 0x80)
|| (returnTrueForNoteOnVelocity0 && (data[2] == 0) && ((data[0] & 0xf0) == 0x90));
}
bool MidiMessage::isNoteOnOrOff() const noexcept
{
const uint8* const data = getRawData();
const int d = data[0] & 0xf0;
return (d == 0x90) || (d == 0x80);
}
int MidiMessage::getNoteNumber() const noexcept
{
return data[1];
return getRawData()[1];
}
void MidiMessage::setNoteNumber (const int newNoteNumber) noexcept
{
if (isNoteOnOrOff())
data[1] = (uint8) (newNoteNumber & 127);
getData()[1] = (uint8) (newNoteNumber & 127);
}
uint8 MidiMessage::getVelocity() const noexcept
{
if (isNoteOnOrOff())
return data[2];
return getRawData()[2];
return 0;
}
@@ -422,24 +385,27 @@ float MidiMessage::getFloatVelocity() const noexcept
void MidiMessage::setVelocity (const float newVelocity) noexcept
{
if (isNoteOnOrOff())
data[2] = MidiHelpers::validVelocity (roundToInt (newVelocity * 127.0f));
getData()[2] = MidiHelpers::validVelocity (roundToInt (newVelocity * 127.0f));
}
void MidiMessage::multiplyVelocity (const float scaleFactor) noexcept
{
if (isNoteOnOrOff())
{
uint8* const data = getData();
data[2] = MidiHelpers::validVelocity (roundToInt (scaleFactor * data[2]));
}
}
bool MidiMessage::isAftertouch() const noexcept
{
return (data[0] & 0xf0) == 0xa0;
return (getRawData()[0] & 0xf0) == 0xa0;
}
int MidiMessage::getAfterTouchValue() const noexcept
{
jassert (isAftertouch());
return data[2];
return getRawData()[2];
}
MidiMessage MidiMessage::aftertouchChange (const int channel,
@@ -457,13 +423,13 @@ MidiMessage MidiMessage::aftertouchChange (const int channel,
bool MidiMessage::isChannelPressure() const noexcept
{
return (data[0] & 0xf0) == 0xd0;
return (getRawData()[0] & 0xf0) == 0xd0;
}
int MidiMessage::getChannelPressureValue() const noexcept
{
jassert (isChannelPressure());
return data[1];
return getRawData()[1];
}
MidiMessage MidiMessage::channelPressureChange (const int channel, const int pressure) noexcept
@@ -474,25 +440,25 @@ MidiMessage MidiMessage::channelPressureChange (const int channel, const int pre
return MidiMessage (MidiHelpers::initialByte (0xd0, channel), pressure & 0x7f);
}
bool MidiMessage::isSustainPedalOn() const noexcept { return isControllerOfType (0x40) && data[2] >= 64; }
bool MidiMessage::isSustainPedalOff() const noexcept { return isControllerOfType (0x40) && data[2] < 64; }
bool MidiMessage::isSustainPedalOn() const noexcept { return isControllerOfType (0x40) && getRawData()[2] >= 64; }
bool MidiMessage::isSustainPedalOff() const noexcept { return isControllerOfType (0x40) && getRawData()[2] < 64; }
bool MidiMessage::isSostenutoPedalOn() const noexcept { return isControllerOfType (0x42) && data[2] >= 64; }
bool MidiMessage::isSostenutoPedalOff() const noexcept { return isControllerOfType (0x42) && data[2] < 64; }
bool MidiMessage::isSostenutoPedalOn() const noexcept { return isControllerOfType (0x42) && getRawData()[2] >= 64; }
bool MidiMessage::isSostenutoPedalOff() const noexcept { return isControllerOfType (0x42) && getRawData()[2] < 64; }
bool MidiMessage::isSoftPedalOn() const noexcept { return isControllerOfType (0x43) && data[2] >= 64; }
bool MidiMessage::isSoftPedalOff() const noexcept { return isControllerOfType (0x43) && data[2] < 64; }
bool MidiMessage::isSoftPedalOn() const noexcept { return isControllerOfType (0x43) && getRawData()[2] >= 64; }
bool MidiMessage::isSoftPedalOff() const noexcept { return isControllerOfType (0x43) && getRawData()[2] < 64; }
bool MidiMessage::isProgramChange() const noexcept
{
return (data[0] & 0xf0) == 0xc0;
return (getRawData()[0] & 0xf0) == 0xc0;
}
int MidiMessage::getProgramChangeNumber() const noexcept
{
jassert (isProgramChange());
return data[1];
return getRawData()[1];
}
MidiMessage MidiMessage::programChange (const int channel, const int programNumber) noexcept
@@ -504,12 +470,13 @@ MidiMessage MidiMessage::programChange (const int channel, const int programNumb
bool MidiMessage::isPitchWheel() const noexcept
{
return (data[0] & 0xf0) == 0xe0;
return (getRawData()[0] & 0xf0) == 0xe0;
}
int MidiMessage::getPitchWheelValue() const noexcept
{
jassert (isPitchWheel());
const uint8* const data = getRawData();
return data[1] | (data[2] << 7);
}
@@ -524,24 +491,25 @@ MidiMessage MidiMessage::pitchWheel (const int channel, const int position) noex
bool MidiMessage::isController() const noexcept
{
return (data[0] & 0xf0) == 0xb0;
return (getRawData()[0] & 0xf0) == 0xb0;
}
bool MidiMessage::isControllerOfType (const int controllerType) const noexcept
{
const uint8* const data = getRawData();
return (data[0] & 0xf0) == 0xb0 && data[1] == controllerType;
}
int MidiMessage::getControllerNumber() const noexcept
{
jassert (isController());
return data[1];
return getRawData()[1];
}
int MidiMessage::getControllerValue() const noexcept
{
jassert (isController());
return data[2];
return getRawData()[2];
}
MidiMessage MidiMessage::controllerEvent (const int channel, const int controllerType, const int value) noexcept
@@ -583,6 +551,7 @@ MidiMessage MidiMessage::allNotesOff (const int channel) noexcept
bool MidiMessage::isAllNotesOff() const noexcept
{
const uint8* const data = getRawData();
return (data[0] & 0xf0) == 0xb0 && data[1] == 123;
}
@@ -593,6 +562,7 @@ MidiMessage MidiMessage::allSoundOff (const int channel) noexcept
bool MidiMessage::isAllSoundOff() const noexcept
{
const uint8* const data = getRawData();
return (data[0] & 0xf0) == 0xb0 && data[1] == 120;
}
@@ -616,7 +586,7 @@ MidiMessage MidiMessage::masterVolume (const float volume)
//==============================================================================
bool MidiMessage::isSysEx() const noexcept
{
return *data == 0xf0;
return *getRawData() == 0xf0;
}
MidiMessage MidiMessage::createSysExMessage (const void* sysexData, const int dataSize)
@@ -641,16 +611,18 @@ int MidiMessage::getSysExDataSize() const noexcept
}
//==============================================================================
bool MidiMessage::isMetaEvent() const noexcept { return *data == 0xff; }
bool MidiMessage::isActiveSense() const noexcept { return *data == 0xfe; }
bool MidiMessage::isMetaEvent() const noexcept { return *getRawData() == 0xff; }
bool MidiMessage::isActiveSense() const noexcept { return *getRawData() == 0xfe; }
int MidiMessage::getMetaEventType() const noexcept
{
const uint8* const data = getRawData();
return *data != 0xff ? -1 : data[1];
}
int MidiMessage::getMetaEventLength() const noexcept
{
const uint8* const data = getRawData();
if (*data == 0xff)
{
int n;
@@ -665,7 +637,7 @@ const uint8* MidiMessage::getMetaEventData() const noexcept
jassert (isMetaEvent());
int n;
const uint8* d = data + 2;
const uint8* d = getRawData() + 2;
readVariableLengthVal (d, n);
return d + n;
}
@@ -686,14 +658,14 @@ String MidiMessage::getTextFromTextMetaEvent() const
CharPointer_UTF8 (textData + getMetaEventLength()));
}
bool MidiMessage::isTrackNameEvent() const noexcept { return (data[1] == 3) && (*data == 0xff); }
bool MidiMessage::isTempoMetaEvent() const noexcept { return (data[1] == 81) && (*data == 0xff); }
bool MidiMessage::isMidiChannelMetaEvent() const noexcept { return (data[1] == 0x20) && (*data == 0xff) && (data[2] == 1); }
bool MidiMessage::isTrackNameEvent() const noexcept { const uint8* data = getRawData(); return (data[1] == 3) && (*data == 0xff); }
bool MidiMessage::isTempoMetaEvent() const noexcept { const uint8* data = getRawData(); return (data[1] == 81) && (*data == 0xff); }
bool MidiMessage::isMidiChannelMetaEvent() const noexcept { const uint8* data = getRawData(); return (data[1] == 0x20) && (*data == 0xff) && (data[2] == 1); }
int MidiMessage::getMidiChannelMetaEventChannel() const noexcept
{
jassert (isMidiChannelMetaEvent());
return data[3] + 1;
return getRawData()[3] + 1;
}
double MidiMessage::getTempoSecondsPerQuarterNote() const noexcept
@@ -748,6 +720,7 @@ MidiMessage MidiMessage::tempoMetaEvent (int microsecondsPerQuarterNote) noexcep
bool MidiMessage::isTimeSignatureMetaEvent() const noexcept
{
const uint8* const data = getRawData();
return (data[1] == 0x58) && (*data == (uint8) 0xff);
}
@@ -816,8 +789,8 @@ MidiMessage MidiMessage::endOfTrack() noexcept
}
//==============================================================================
bool MidiMessage::isSongPositionPointer() const noexcept { return *data == 0xf2; }
int MidiMessage::getSongPositionPointerMidiBeat() const noexcept { return data[1] | (data[2] << 7); }
bool MidiMessage::isSongPositionPointer() const noexcept { return *getRawData() == 0xf2; }
int MidiMessage::getSongPositionPointerMidiBeat() const noexcept { const uint8* data = getRawData(); return data[1] | (data[2] << 7); }
MidiMessage MidiMessage::songPositionPointer (const int positionInMidiBeats) noexcept
{
@@ -826,21 +799,21 @@ MidiMessage MidiMessage::songPositionPointer (const int positionInMidiBeats) noe
(positionInMidiBeats >> 7) & 127);
}
bool MidiMessage::isMidiStart() const noexcept { return *data == 0xfa; }
bool MidiMessage::isMidiStart() const noexcept { return *getRawData() == 0xfa; }
MidiMessage MidiMessage::midiStart() noexcept { return MidiMessage (0xfa); }
bool MidiMessage::isMidiContinue() const noexcept { return *data == 0xfb; }
bool MidiMessage::isMidiContinue() const noexcept { return *getRawData() == 0xfb; }
MidiMessage MidiMessage::midiContinue() noexcept { return MidiMessage (0xfb); }
bool MidiMessage::isMidiStop() const noexcept { return *data == 0xfc; }
bool MidiMessage::isMidiStop() const noexcept { return *getRawData() == 0xfc; }
MidiMessage MidiMessage::midiStop() noexcept { return MidiMessage (0xfc); }
bool MidiMessage::isMidiClock() const noexcept { return *data == 0xf8; }
bool MidiMessage::isMidiClock() const noexcept { return *getRawData() == 0xf8; }
MidiMessage MidiMessage::midiClock() noexcept { return MidiMessage (0xf8); }
bool MidiMessage::isQuarterFrame() const noexcept { return *data == 0xf1; }
int MidiMessage::getQuarterFrameSequenceNumber() const noexcept { return ((int) data[1]) >> 4; }
int MidiMessage::getQuarterFrameValue() const noexcept { return ((int) data[1]) & 0x0f; }
bool MidiMessage::isQuarterFrame() const noexcept { return *getRawData() == 0xf1; }
int MidiMessage::getQuarterFrameSequenceNumber() const noexcept { return ((int) getRawData()[1]) >> 4; }
int MidiMessage::getQuarterFrameValue() const noexcept { return ((int) getRawData()[1]) & 0x0f; }
MidiMessage MidiMessage::quarterFrame (const int sequenceNumber, const int value) noexcept
{
@@ -849,6 +822,8 @@ MidiMessage MidiMessage::quarterFrame (const int sequenceNumber, const int value
bool MidiMessage::isFullFrame() const noexcept
{
const uint8* const data = getRawData();
return data[0] == 0xf0
&& data[1] == 0x7f
&& size >= 10
@@ -861,6 +836,7 @@ void MidiMessage::getFullFrameParameters (int& hours, int& minutes, int& seconds
{
jassert (isFullFrame());
const uint8* const data = getRawData();
timecodeType = (SmpteTimecodeType) (data[5] >> 5);
hours = data[5] & 0x1f;
minutes = data[6];
@@ -884,6 +860,7 @@ MidiMessage MidiMessage::fullFrame (const int hours, const int minutes,
bool MidiMessage::isMidiMachineControlMessage() const noexcept
{
const uint8* const data = getRawData();
return data[0] == 0xf0
&& data[1] == 0x7f
&& data[3] == 0x06
@@ -894,7 +871,7 @@ MidiMessage::MidiMachineControlCommand MidiMessage::getMidiMachineControlCommand
{
jassert (isMidiMachineControlMessage());
return (MidiMachineControlCommand) data[4];
return (MidiMachineControlCommand) getRawData()[4];
}
MidiMessage MidiMessage::midiMachineControlCommand (MidiMessage::MidiMachineControlCommand command)
@@ -907,6 +884,7 @@ MidiMessage MidiMessage::midiMachineControlCommand (MidiMessage::MidiMachineCont
//==============================================================================
bool MidiMessage::isMidiMachineControlGoto (int& hours, int& minutes, int& seconds, int& frames) const noexcept
{
const uint8* const data = getRawData();
if (size >= 12
&& data[0] == 0xf0
&& data[1] == 0x7f
@@ -967,29 +945,38 @@ const char* MidiMessage::getGMInstrumentName (const int n)
{
static const char* names[] =
{
"Acoustic Grand Piano", "Bright Acoustic Piano", "Electric Grand Piano", "Honky-tonk Piano",
"Electric Piano 1", "Electric Piano 2", "Harpsichord", "Clavinet", "Celesta", "Glockenspiel",
"Music Box", "Vibraphone", "Marimba", "Xylophone", "Tubular Bells", "Dulcimer", "Drawbar Organ",
"Percussive Organ", "Rock Organ", "Church Organ", "Reed Organ", "Accordion", "Harmonica",
"Tango Accordion", "Acoustic Guitar (nylon)", "Acoustic Guitar (steel)", "Electric Guitar (jazz)",
"Electric Guitar (clean)", "Electric Guitar (mute)", "Overdriven Guitar", "Distortion Guitar",
"Guitar Harmonics", "Acoustic Bass", "Electric Bass (finger)", "Electric Bass (pick)",
"Fretless Bass", "Slap Bass 1", "Slap Bass 2", "Synth Bass 1", "Synth Bass 2", "Violin",
"Viola", "Cello", "Contrabass", "Tremolo Strings", "Pizzicato Strings", "Orchestral Harp",
"Timpani", "String Ensemble 1", "String Ensemble 2", "SynthStrings 1", "SynthStrings 2",
"Choir Aahs", "Voice Oohs", "Synth Voice", "Orchestra Hit", "Trumpet", "Trombone", "Tuba",
"Muted Trumpet", "French Horn", "Brass Section", "SynthBrass 1", "SynthBrass 2", "Soprano Sax",
"Alto Sax", "Tenor Sax", "Baritone Sax", "Oboe", "English Horn", "Bassoon", "Clarinet",
"Piccolo", "Flute", "Recorder", "Pan Flute", "Blown Bottle", "Shakuhachi", "Whistle",
"Ocarina", "Lead 1 (square)", "Lead 2 (sawtooth)", "Lead 3 (calliope)", "Lead 4 (chiff)",
"Lead 5 (charang)", "Lead 6 (voice)", "Lead 7 (fifths)", "Lead 8 (bass+lead)", "Pad 1 (new age)",
"Pad 2 (warm)", "Pad 3 (polysynth)", "Pad 4 (choir)", "Pad 5 (bowed)", "Pad 6 (metallic)",
"Pad 7 (halo)", "Pad 8 (sweep)", "FX 1 (rain)", "FX 2 (soundtrack)", "FX 3 (crystal)",
"FX 4 (atmosphere)", "FX 5 (brightness)", "FX 6 (goblins)", "FX 7 (echoes)", "FX 8 (sci-fi)",
"Sitar", "Banjo", "Shamisen", "Koto", "Kalimba", "Bag pipe", "Fiddle", "Shanai", "Tinkle Bell",
"Agogo", "Steel Drums", "Woodblock", "Taiko Drum", "Melodic Tom", "Synth Drum", "Reverse Cymbal",
"Guitar Fret Noise", "Breath Noise", "Seashore", "Bird Tweet", "Telephone Ring", "Helicopter",
"Applause", "Gunshot"
NEEDS_TRANS("Acoustic Grand Piano"), NEEDS_TRANS("Bright Acoustic Piano"), NEEDS_TRANS("Electric Grand Piano"), NEEDS_TRANS("Honky-tonk Piano"),
NEEDS_TRANS("Electric Piano 1"), NEEDS_TRANS("Electric Piano 2"), NEEDS_TRANS("Harpsichord"), NEEDS_TRANS("Clavinet"),
NEEDS_TRANS("Celesta"), NEEDS_TRANS("Glockenspiel"), NEEDS_TRANS("Music Box"), NEEDS_TRANS("Vibraphone"),
NEEDS_TRANS("Marimba"), NEEDS_TRANS("Xylophone"), NEEDS_TRANS("Tubular Bells"), NEEDS_TRANS("Dulcimer"),
NEEDS_TRANS("Drawbar Organ"), NEEDS_TRANS("Percussive Organ"), NEEDS_TRANS("Rock Organ"), NEEDS_TRANS("Church Organ"),
NEEDS_TRANS("Reed Organ"), NEEDS_TRANS("Accordion"), NEEDS_TRANS("Harmonica"), NEEDS_TRANS("Tango Accordion"),
NEEDS_TRANS("Acoustic Guitar (nylon)"), NEEDS_TRANS("Acoustic Guitar (steel)"), NEEDS_TRANS("Electric Guitar (jazz)"), NEEDS_TRANS("Electric Guitar (clean)"),
NEEDS_TRANS("Electric Guitar (mute)"), NEEDS_TRANS("Overdriven Guitar"), NEEDS_TRANS("Distortion Guitar"), NEEDS_TRANS("Guitar Harmonics"),
NEEDS_TRANS("Acoustic Bass"), NEEDS_TRANS("Electric Bass (finger)"), NEEDS_TRANS("Electric Bass (pick)"), NEEDS_TRANS("Fretless Bass"),
NEEDS_TRANS("Slap Bass 1"), NEEDS_TRANS("Slap Bass 2"), NEEDS_TRANS("Synth Bass 1"), NEEDS_TRANS("Synth Bass 2"),
NEEDS_TRANS("Violin"), NEEDS_TRANS("Viola"), NEEDS_TRANS("Cello"), NEEDS_TRANS("Contrabass"),
NEEDS_TRANS("Tremolo Strings"), NEEDS_TRANS("Pizzicato Strings"), NEEDS_TRANS("Orchestral Harp"), NEEDS_TRANS("Timpani"),
NEEDS_TRANS("String Ensemble 1"), NEEDS_TRANS("String Ensemble 2"), NEEDS_TRANS("SynthStrings 1"), NEEDS_TRANS("SynthStrings 2"),
NEEDS_TRANS("Choir Aahs"), NEEDS_TRANS("Voice Oohs"), NEEDS_TRANS("Synth Voice"), NEEDS_TRANS("Orchestra Hit"),
NEEDS_TRANS("Trumpet"), NEEDS_TRANS("Trombone"), NEEDS_TRANS("Tuba"), NEEDS_TRANS("Muted Trumpet"),
NEEDS_TRANS("French Horn"), NEEDS_TRANS("Brass Section"), NEEDS_TRANS("SynthBrass 1"), NEEDS_TRANS("SynthBrass 2"),
NEEDS_TRANS("Soprano Sax"), NEEDS_TRANS("Alto Sax"), NEEDS_TRANS("Tenor Sax"), NEEDS_TRANS("Baritone Sax"),
NEEDS_TRANS("Oboe"), NEEDS_TRANS("English Horn"), NEEDS_TRANS("Bassoon"), NEEDS_TRANS("Clarinet"),
NEEDS_TRANS("Piccolo"), NEEDS_TRANS("Flute"), NEEDS_TRANS("Recorder"), NEEDS_TRANS("Pan Flute"),
NEEDS_TRANS("Blown Bottle"), NEEDS_TRANS("Shakuhachi"), NEEDS_TRANS("Whistle"), NEEDS_TRANS("Ocarina"),
NEEDS_TRANS("Lead 1 (square)"), NEEDS_TRANS("Lead 2 (sawtooth)"), NEEDS_TRANS("Lead 3 (calliope)"), NEEDS_TRANS("Lead 4 (chiff)"),
NEEDS_TRANS("Lead 5 (charang)"), NEEDS_TRANS("Lead 6 (voice)"), NEEDS_TRANS("Lead 7 (fifths)"), NEEDS_TRANS("Lead 8 (bass+lead)"),
NEEDS_TRANS("Pad 1 (new age)"), NEEDS_TRANS("Pad 2 (warm)"), NEEDS_TRANS("Pad 3 (polysynth)"), NEEDS_TRANS("Pad 4 (choir)"),
NEEDS_TRANS("Pad 5 (bowed)"), NEEDS_TRANS("Pad 6 (metallic)"), NEEDS_TRANS("Pad 7 (halo)"), NEEDS_TRANS("Pad 8 (sweep)"),
NEEDS_TRANS("FX 1 (rain)"), NEEDS_TRANS("FX 2 (soundtrack)"), NEEDS_TRANS("FX 3 (crystal)"), NEEDS_TRANS("FX 4 (atmosphere)"),
NEEDS_TRANS("FX 5 (brightness)"), NEEDS_TRANS("FX 6 (goblins)"), NEEDS_TRANS("FX 7 (echoes)"), NEEDS_TRANS("FX 8 (sci-fi)"),
NEEDS_TRANS("Sitar"), NEEDS_TRANS("Banjo"), NEEDS_TRANS("Shamisen"), NEEDS_TRANS("Koto"),
NEEDS_TRANS("Kalimba"), NEEDS_TRANS("Bag pipe"), NEEDS_TRANS("Fiddle"), NEEDS_TRANS("Shanai"),
NEEDS_TRANS("Tinkle Bell"), NEEDS_TRANS("Agogo"), NEEDS_TRANS("Steel Drums"), NEEDS_TRANS("Woodblock"),
NEEDS_TRANS("Taiko Drum"), NEEDS_TRANS("Melodic Tom"), NEEDS_TRANS("Synth Drum"), NEEDS_TRANS("Reverse Cymbal"),
NEEDS_TRANS("Guitar Fret Noise"), NEEDS_TRANS("Breath Noise"), NEEDS_TRANS("Seashore"), NEEDS_TRANS("Bird Tweet"),
NEEDS_TRANS("Telephone Ring"), NEEDS_TRANS("Helicopter"), NEEDS_TRANS("Applause"), NEEDS_TRANS("Gunshot")
};
return isPositiveAndBelow (n, numElementsInArray (names)) ? names[n] : nullptr;
@@ -999,10 +986,10 @@ const char* MidiMessage::getGMInstrumentBankName (const int n)
{
static const char* names[] =
{
"Piano", "Chromatic Percussion", "Organ", "Guitar",
"Bass", "Strings", "Ensemble", "Brass",
"Reed", "Pipe", "Synth Lead", "Synth Pad",
"Synth Effects", "Ethnic", "Percussive", "Sound Effects"
NEEDS_TRANS("Piano"), NEEDS_TRANS("Chromatic Percussion"), NEEDS_TRANS("Organ"), NEEDS_TRANS("Guitar"),
NEEDS_TRANS("Bass"), NEEDS_TRANS("Strings"), NEEDS_TRANS("Ensemble"), NEEDS_TRANS("Brass"),
NEEDS_TRANS("Reed"), NEEDS_TRANS("Pipe"), NEEDS_TRANS("Synth Lead"), NEEDS_TRANS("Synth Pad"),
NEEDS_TRANS("Synth Effects"), NEEDS_TRANS("Ethnic"), NEEDS_TRANS("Percussive"), NEEDS_TRANS("Sound Effects")
};
return isPositiveAndBelow (n, numElementsInArray (names)) ? names[n] : nullptr;
@@ -1012,15 +999,18 @@ const char* MidiMessage::getRhythmInstrumentName (const int n)
{
static const char* names[] =
{
"Acoustic Bass Drum", "Bass Drum 1", "Side Stick", "Acoustic Snare",
"Hand Clap", "Electric Snare", "Low Floor Tom", "Closed Hi-Hat", "High Floor Tom",
"Pedal Hi-Hat", "Low Tom", "Open Hi-Hat", "Low-Mid Tom", "Hi-Mid Tom", "Crash Cymbal 1",
"High Tom", "Ride Cymbal 1", "Chinese Cymbal", "Ride Bell", "Tambourine", "Splash Cymbal",
"Cowbell", "Crash Cymbal 2", "Vibraslap", "Ride Cymbal 2", "Hi Bongo", "Low Bongo",
"Mute Hi Conga", "Open Hi Conga", "Low Conga", "High Timbale", "Low Timbale", "High Agogo",
"Low Agogo", "Cabasa", "Maracas", "Short Whistle", "Long Whistle", "Short Guiro",
"Long Guiro", "Claves", "Hi Wood Block", "Low Wood Block", "Mute Cuica", "Open Cuica",
"Mute Triangle", "Open Triangle"
NEEDS_TRANS("Acoustic Bass Drum"), NEEDS_TRANS("Bass Drum 1"), NEEDS_TRANS("Side Stick"), NEEDS_TRANS("Acoustic Snare"),
NEEDS_TRANS("Hand Clap"), NEEDS_TRANS("Electric Snare"), NEEDS_TRANS("Low Floor Tom"), NEEDS_TRANS("Closed Hi-Hat"),
NEEDS_TRANS("High Floor Tom"), NEEDS_TRANS("Pedal Hi-Hat"), NEEDS_TRANS("Low Tom"), NEEDS_TRANS("Open Hi-Hat"),
NEEDS_TRANS("Low-Mid Tom"), NEEDS_TRANS("Hi-Mid Tom"), NEEDS_TRANS("Crash Cymbal 1"), NEEDS_TRANS("High Tom"),
NEEDS_TRANS("Ride Cymbal 1"), NEEDS_TRANS("Chinese Cymbal"), NEEDS_TRANS("Ride Bell"), NEEDS_TRANS("Tambourine"),
NEEDS_TRANS("Splash Cymbal"), NEEDS_TRANS("Cowbell"), NEEDS_TRANS("Crash Cymbal 2"), NEEDS_TRANS("Vibraslap"),
NEEDS_TRANS("Ride Cymbal 2"), NEEDS_TRANS("Hi Bongo"), NEEDS_TRANS("Low Bongo"), NEEDS_TRANS("Mute Hi Conga"),
NEEDS_TRANS("Open Hi Conga"), NEEDS_TRANS("Low Conga"), NEEDS_TRANS("High Timbale"), NEEDS_TRANS("Low Timbale"),
NEEDS_TRANS("High Agogo"), NEEDS_TRANS("Low Agogo"), NEEDS_TRANS("Cabasa"), NEEDS_TRANS("Maracas"),
NEEDS_TRANS("Short Whistle"), NEEDS_TRANS("Long Whistle"), NEEDS_TRANS("Short Guiro"), NEEDS_TRANS("Long Guiro"),
NEEDS_TRANS("Claves"), NEEDS_TRANS("Hi Wood Block"), NEEDS_TRANS("Low Wood Block"), NEEDS_TRANS("Mute Cuica"),
NEEDS_TRANS("Open Cuica"), NEEDS_TRANS("Mute Triangle"), NEEDS_TRANS("Open Triangle")
};
return (n >= 35 && n <= 81) ? names [n - 35] : nullptr;
@@ -1030,28 +1020,38 @@ const char* MidiMessage::getControllerName (const int n)
{
static const char* names[] =
{
"Bank Select", "Modulation Wheel (coarse)", "Breath controller (coarse)",
0, "Foot Pedal (coarse)", "Portamento Time (coarse)",
"Data Entry (coarse)", "Volume (coarse)", "Balance (coarse)",
0, "Pan position (coarse)", "Expression (coarse)", "Effect Control 1 (coarse)",
"Effect Control 2 (coarse)", 0, 0, "General Purpose Slider 1", "General Purpose Slider 2",
"General Purpose Slider 3", "General Purpose Slider 4", 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, "Bank Select (fine)", "Modulation Wheel (fine)", "Breath controller (fine)",
0, "Foot Pedal (fine)", "Portamento Time (fine)", "Data Entry (fine)", "Volume (fine)",
"Balance (fine)", 0, "Pan position (fine)", "Expression (fine)", "Effect Control 1 (fine)",
"Effect Control 2 (fine)", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
"Hold Pedal (on/off)", "Portamento (on/off)", "Sustenuto Pedal (on/off)", "Soft Pedal (on/off)",
"Legato Pedal (on/off)", "Hold 2 Pedal (on/off)", "Sound Variation", "Sound Timbre",
"Sound Release Time", "Sound Attack Time", "Sound Brightness", "Sound Control 6",
"Sound Control 7", "Sound Control 8", "Sound Control 9", "Sound Control 10",
"General Purpose Button 1 (on/off)", "General Purpose Button 2 (on/off)",
"General Purpose Button 3 (on/off)", "General Purpose Button 4 (on/off)",
0, 0, 0, 0, 0, 0, 0, "Reverb Level", "Tremolo Level", "Chorus Level", "Celeste Level",
"Phaser Level", "Data Button increment", "Data Button decrement", "Non-registered Parameter (fine)",
"Non-registered Parameter (coarse)", "Registered Parameter (fine)", "Registered Parameter (coarse)",
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "All Sound Off", "All Controllers Off",
"Local Keyboard (on/off)", "All Notes Off", "Omni Mode Off", "Omni Mode On", "Mono Operation",
"Poly Operation"
NEEDS_TRANS("Bank Select"), NEEDS_TRANS("Modulation Wheel (coarse)"), NEEDS_TRANS("Breath controller (coarse)"),
nullptr,
NEEDS_TRANS("Foot Pedal (coarse)"), NEEDS_TRANS("Portamento Time (coarse)"), NEEDS_TRANS("Data Entry (coarse)"),
NEEDS_TRANS("Volume (coarse)"), NEEDS_TRANS("Balance (coarse)"),
nullptr,
NEEDS_TRANS("Pan position (coarse)"), NEEDS_TRANS("Expression (coarse)"), NEEDS_TRANS("Effect Control 1 (coarse)"),
NEEDS_TRANS("Effect Control 2 (coarse)"),
nullptr, nullptr,
NEEDS_TRANS("General Purpose Slider 1"), NEEDS_TRANS("General Purpose Slider 2"),
NEEDS_TRANS("General Purpose Slider 3"), NEEDS_TRANS("General Purpose Slider 4"),
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
NEEDS_TRANS("Bank Select (fine)"), NEEDS_TRANS("Modulation Wheel (fine)"), NEEDS_TRANS("Breath controller (fine)"),
nullptr,
NEEDS_TRANS("Foot Pedal (fine)"), NEEDS_TRANS("Portamento Time (fine)"), NEEDS_TRANS("Data Entry (fine)"), NEEDS_TRANS("Volume (fine)"),
NEEDS_TRANS("Balance (fine)"), nullptr, NEEDS_TRANS("Pan position (fine)"), NEEDS_TRANS("Expression (fine)"),
NEEDS_TRANS("Effect Control 1 (fine)"), NEEDS_TRANS("Effect Control 2 (fine)"),
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
NEEDS_TRANS("Hold Pedal (on/off)"), NEEDS_TRANS("Portamento (on/off)"), NEEDS_TRANS("Sustenuto Pedal (on/off)"), NEEDS_TRANS("Soft Pedal (on/off)"),
NEEDS_TRANS("Legato Pedal (on/off)"), NEEDS_TRANS("Hold 2 Pedal (on/off)"), NEEDS_TRANS("Sound Variation"), NEEDS_TRANS("Sound Timbre"),
NEEDS_TRANS("Sound Release Time"), NEEDS_TRANS("Sound Attack Time"), NEEDS_TRANS("Sound Brightness"), NEEDS_TRANS("Sound Control 6"),
NEEDS_TRANS("Sound Control 7"), NEEDS_TRANS("Sound Control 8"), NEEDS_TRANS("Sound Control 9"), NEEDS_TRANS("Sound Control 10"),
NEEDS_TRANS("General Purpose Button 1 (on/off)"), NEEDS_TRANS("General Purpose Button 2 (on/off)"),
NEEDS_TRANS("General Purpose Button 3 (on/off)"), NEEDS_TRANS("General Purpose Button 4 (on/off)"),
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
NEEDS_TRANS("Reverb Level"), NEEDS_TRANS("Tremolo Level"), NEEDS_TRANS("Chorus Level"), NEEDS_TRANS("Celeste Level"),
NEEDS_TRANS("Phaser Level"), NEEDS_TRANS("Data Button increment"), NEEDS_TRANS("Data Button decrement"), NEEDS_TRANS("Non-registered Parameter (fine)"),
NEEDS_TRANS("Non-registered Parameter (coarse)"), NEEDS_TRANS("Registered Parameter (fine)"), NEEDS_TRANS("Registered Parameter (coarse)"),
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
NEEDS_TRANS("All Sound Off"), NEEDS_TRANS("All Controllers Off"), NEEDS_TRANS("Local Keyboard (on/off)"), NEEDS_TRANS("All Notes Off"),
NEEDS_TRANS("Omni Mode Off"), NEEDS_TRANS("Omni Mode On"), NEEDS_TRANS("Mono Operation"), NEEDS_TRANS("Poly Operation")
};
return isPositiveAndBelow (n, numElementsInArray (names)) ? names[n] : nullptr;


+ 8
- 9
source/modules/juce_audio_basics/midi/juce_MidiMessage.h View File

@@ -114,12 +114,12 @@ public:
/** Returns a pointer to the raw midi data.
@see getRawDataSize
*/
const uint8* getRawData() const noexcept { return data; }
const uint8* getRawData() const noexcept { return allocatedData != nullptr ? allocatedData.getData() : preallocatedData.asBytes; }
/** Returns the number of bytes of data in the message.
@see getRawData
*/
int getRawDataSize() const noexcept { return size; }
int getRawDataSize() const noexcept { return size; }
//==============================================================================
/** Returns the timestamp associated with this message.
@@ -138,18 +138,18 @@ public:
@see setTimeStamp, addToTimeStamp
*/
double getTimeStamp() const noexcept { return timeStamp; }
double getTimeStamp() const noexcept { return timeStamp; }
/** Changes the message's associated timestamp.
The units for the timestamp will be application-specific - see the notes for getTimeStamp().
@see addToTimeStamp, getTimeStamp
*/
void setTimeStamp (double newTimestamp) noexcept { timeStamp = newTimestamp; }
void setTimeStamp (double newTimestamp) noexcept { timeStamp = newTimestamp; }
/** Adds a value to the message's timestamp.
The units for the timestamp will be application-specific.
*/
void addToTimeStamp (double delta) noexcept { timeStamp += delta; }
void addToTimeStamp (double delta) noexcept { timeStamp += delta; }
//==============================================================================
/** Returns the midi channel associated with the message.
@@ -914,7 +914,7 @@ public:
private:
//==============================================================================
double timeStamp;
uint8* data;
HeapBlock<uint8> allocatedData;
int size;
#ifndef DOXYGEN
@@ -925,9 +925,8 @@ private:
} preallocatedData;
#endif
void freeData() noexcept;
void setToUseInternalData() noexcept;
bool usesAllocatedData() const noexcept;
inline uint8* getData() noexcept { return allocatedData != nullptr ? allocatedData.getData() : preallocatedData.asBytes; }
uint8* allocateSpace (int);
};
#endif // JUCE_MIDIMESSAGE_H_INCLUDED

+ 1
- 4
source/modules/juce_audio_basics/midi/juce_MidiMessageSequence.cpp View File

@@ -28,10 +28,7 @@ MidiMessageSequence::MidiMessageSequence()
MidiMessageSequence::MidiMessageSequence (const MidiMessageSequence& other)
{
list.ensureStorageAllocated (other.list.size());
for (int i = 0; i < other.list.size(); ++i)
list.add (new MidiEventHolder (other.list.getUnchecked(i)->message));
list.addCopiesOf (other.list);
}
MidiMessageSequence& MidiMessageSequence::operator= (const MidiMessageSequence& other)


+ 9
- 22
source/modules/juce_audio_basics/midi/juce_MidiMessageSequence.h View File

@@ -43,10 +43,10 @@ public:
MidiMessageSequence();
/** Creates a copy of another sequence. */
MidiMessageSequence (const MidiMessageSequence& other);
MidiMessageSequence (const MidiMessageSequence&);
/** Replaces this sequence with another one. */
MidiMessageSequence& operator= (const MidiMessageSequence& other);
MidiMessageSequence& operator= (const MidiMessageSequence&);
/** Destructor. */
~MidiMessageSequence();
@@ -66,13 +66,12 @@ public:
/** Destructor. */
~MidiEventHolder();
/** The message itself, whose timestamp is used to specify the event's time.
*/
/** The message itself, whose timestamp is used to specify the event's time. */
MidiMessage message;
/** The matching note-off event (if this is a note-on event).
If this isn't a note-on, this pointer will be null.
If this isn't a note-on, this pointer will be nullptr.
Use the MidiMessageSequence::updateMatchedPairs() method to keep these
note-offs up-to-date after events have been moved around in the sequence
@@ -83,7 +82,7 @@ public:
private:
//==============================================================================
friend class MidiMessageSequence;
MidiEventHolder (const MidiMessage& message);
MidiEventHolder (const MidiMessage&);
JUCE_LEAK_DETECTOR (MidiEventHolder)
};
@@ -98,17 +97,13 @@ public:
MidiEventHolder* getEventPointer (int index) const;
/** 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;
/** 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;
@@ -117,7 +112,6 @@ public:
int getIndexOf (MidiEventHolder* event) const;
/** 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.
*/
@@ -125,19 +119,16 @@ public:
//==============================================================================
/** Returns the timestamp of the first event in the sequence.
@see getEndTime
*/
double getStartTime() const;
/** Returns the timestamp of the last event in the sequence.
@see getStartTime
*/
double getEndTime() const;
/** 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;
@@ -190,7 +181,7 @@ public:
//==============================================================================
/** Makes sure all the note-on and note-off pairs are up-to-date.
Call this after moving messages about or deleting/adding messages, and it
Call this after re-ordering messages or deleting/adding messages, and it
will scan the list and make sure all the note-offs in the MidiEventHolder
structures are pointing at the correct ones.
*/
@@ -216,7 +207,6 @@ public:
bool alsoIncludeMetaEvents) const;
/** Copies all midi sys-ex messages to another sequence.
@param destSequence this is the sequence to which any sys-exes in this sequence
will be added
@see extractMidiChannelMessages
@@ -224,17 +214,14 @@ public:
void extractSysExMessages (MidiMessageSequence& destSequence) const;
/** Removes any messages in this sequence that have a specific midi channel.
@param channelNumberToRemove the midi channel to look for, in the range 1 to 16
*/
void deleteMidiChannelMessages (int channelNumberToRemove);
/** Removes any sys-ex messages from this sequence.
*/
/** Removes any sys-ex messages from this sequence. */
void deleteSysExMessages();
/** 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);
@@ -264,12 +251,12 @@ public:
//==============================================================================
/** Swaps this sequence with another one. */
void swapWith (MidiMessageSequence& other) noexcept;
void swapWith (MidiMessageSequence&) noexcept;
private:
//==============================================================================
friend class MidiFile;
OwnedArray <MidiEventHolder> list;
OwnedArray<MidiEventHolder> list;
JUCE_LEAK_DETECTOR (MidiMessageSequence)
};


+ 20
- 0
source/modules/juce_audio_basics/synthesisers/juce_Synthesiser.cpp View File

@@ -56,6 +56,8 @@ void SynthesiserVoice::clearCurrentNote()
currentlyPlayingSound = nullptr;
}
void SynthesiserVoice::aftertouchChanged (int) {}
//==============================================================================
Synthesiser::Synthesiser()
: sampleRate (0),
@@ -191,6 +193,10 @@ void Synthesiser::handleMidiEvent (const MidiMessage& m)
handlePitchWheel (channel, wheelPos);
}
else if (m.isAftertouch())
{
handleAftertouch (m.getChannel(), m.getNoteNumber(), m.getAfterTouchValue());
}
else if (m.isController())
{
handleController (m.getChannel(), m.getControllerNumber(), m.getControllerValue());
@@ -338,6 +344,20 @@ void Synthesiser::handleController (const int midiChannel,
}
}
void Synthesiser::handleAftertouch (int midiChannel, int midiNoteNumber, int aftertouchValue)
{
const ScopedLock sl (lock);
for (int i = voices.size(); --i >= 0;)
{
SynthesiserVoice* const voice = voices.getUnchecked (i);
if (voice->getCurrentlyPlayingNote() == midiNoteNumber
&& (midiChannel <= 0 || voice->isPlayingChannel (midiChannel)))
voice->aftertouchChanged (aftertouchValue);
}
}
void Synthesiser::handleSustainPedal (int midiChannel, bool isDown)
{
jassert (midiChannel > 0 && midiChannel <= 16);


+ 31
- 5
source/modules/juce_audio_basics/synthesisers/juce_Synthesiser.h View File

@@ -116,7 +116,6 @@ public:
virtual bool canPlaySound (SynthesiserSound*) = 0;
/** Called to start a new note.
This will be called during the rendering callback, so must be fast and thread-safe.
*/
virtual void startNote (int midiNoteNumber,
@@ -142,12 +141,17 @@ public:
/** 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.
*/
virtual void pitchWheelMoved (int newValue) = 0;
virtual void pitchWheelMoved (int newPitchWheelValue) = 0;
/** Called to let the voice know that a midi controller has been moved.
This will be called during the rendering callback, so must be fast and thread-safe.
*/
virtual void controllerMoved (int controllerNumber, int newValue) = 0;
virtual void controllerMoved (int controllerNumber, int newControllerValue) = 0;
/** Called to let the voice know that the aftertouch has changed.
This will be called during the rendering callback, so must be fast and thread-safe.
*/
virtual void aftertouchChanged (int newAftertouchValue);
//==============================================================================
/** Renders the next block of data for this voice.
@@ -186,6 +190,14 @@ public:
*/
void setCurrentPlaybackSampleRate (double newRate);
/** 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
sostenuto pedal is down).
*/
bool isKeyDown() const noexcept { return keyIsDown; }
/** Returns true if the sostenuto pedal is currently active for this voice. */
bool isSostenutoPedalDown() const noexcept { return sostenutoPedalDown; }
protected:
//==============================================================================
@@ -218,8 +230,7 @@ private:
int currentlyPlayingNote;
uint32 noteOnTime;
SynthesiserSound::Ptr currentlyPlayingSound;
bool keyIsDown; // the voice may still be playing when the key is not down (i.e. sustain pedal)
bool sostenutoPedalDown;
bool keyIsDown, sostenutoPedalDown;
JUCE_LEAK_DETECTOR (SynthesiserVoice)
};
@@ -400,6 +411,21 @@ public:
int controllerNumber,
int controllerValue);
/** Sends an aftertouch message.
This will send an aftertouch message to any voices that are playing sounds on
the given midi channel and note number.
This method will be called automatically according to the midi data passed into
renderNextBlock(), but may be called explicitly too.
@param midiChannel the midi channel, from 1 to 16 inclusive
@param midiNoteNumber the midi note number, 0 to 127
@param aftertouchValue the aftertouch value, between 0 and 127,
as returned by MidiMessage::getAftertouchValue()
*/
virtual void handleAftertouch (int midiChannel, int midiNoteNumber, int aftertouchValue);
/** Handles a sustain pedal event. */
virtual void handleSustainPedal (int midiChannel, bool isDown);


Loading…
Cancel
Save