Browse Source

Update to latest juce

tags/1.9.7
falkTX 9 years ago
parent
commit
6c7b077704
100 changed files with 1808 additions and 926 deletions
  1. +5
    -2
      source/modules/juce_audio_basics/buffers/juce_AudioSampleBuffer.cpp
  2. +131
    -11
      source/modules/juce_audio_basics/buffers/juce_FloatVectorOperations.cpp
  3. +6
    -0
      source/modules/juce_audio_basics/buffers/juce_FloatVectorOperations.h
  4. +1
    -1
      source/modules/juce_audio_basics/effects/juce_Reverb.h
  5. +3
    -0
      source/modules/juce_audio_basics/juce_audio_basics.cpp
  6. +1
    -1
      source/modules/juce_audio_basics/midi/juce_MidiKeyboardState.cpp
  7. +96
    -26
      source/modules/juce_audio_basics/synthesisers/juce_Synthesiser.cpp
  8. +43
    -0
      source/modules/juce_audio_basics/synthesisers/juce_Synthesiser.h
  9. +5
    -0
      source/modules/juce_audio_devices/audio_io/juce_AudioDeviceManager.cpp
  10. +21
    -21
      source/modules/juce_audio_devices/native/juce_linux_ALSA.cpp
  11. +7
    -7
      source/modules/juce_audio_devices/native/juce_linux_Midi.cpp
  12. +6
    -0
      source/modules/juce_audio_devices/native/juce_mac_CoreAudio.cpp
  13. +7
    -5
      source/modules/juce_audio_devices/native/juce_win32_ASIO.cpp
  14. +2
    -2
      source/modules/juce_audio_formats/codecs/juce_LAMEEncoderAudioFormat.cpp
  15. +2
    -3
      source/modules/juce_audio_formats/codecs/juce_MP3AudioFormat.cpp
  16. +5
    -5
      source/modules/juce_audio_formats/codecs/juce_QuickTimeAudioFormat.cpp
  17. +7
    -5
      source/modules/juce_audio_formats/codecs/juce_WavAudioFormat.cpp
  18. +1
    -1
      source/modules/juce_audio_formats/codecs/oggvorbis/libvorbis-1.3.2/lib/floor1.c
  19. +1
    -1
      source/modules/juce_audio_formats/format/juce_AudioFormat.h
  20. +2
    -2
      source/modules/juce_audio_formats/format/juce_AudioFormatReaderSource.h
  21. +1
    -1
      source/modules/juce_audio_formats/sampler/juce_Sampler.h
  22. +40
    -40
      source/modules/juce_audio_processors/format_types/juce_AudioUnitPluginFormat.mm
  23. +1
    -1
      source/modules/juce_audio_processors/format_types/juce_LADSPAPluginFormat.cpp
  24. +2
    -2
      source/modules/juce_audio_processors/format_types/juce_VST3Common.h
  25. +87
    -58
      source/modules/juce_audio_processors/format_types/juce_VSTPluginFormat.cpp
  26. +3
    -1
      source/modules/juce_audio_processors/processors/juce_AudioPlayHead.h
  27. +4
    -4
      source/modules/juce_audio_processors/processors/juce_AudioProcessor.cpp
  28. +57
    -5
      source/modules/juce_audio_processors/processors/juce_AudioProcessor.h
  29. +1
    -1
      source/modules/juce_audio_processors/processors/juce_AudioProcessorGraph.h
  30. +1
    -1
      source/modules/juce_audio_processors/processors/juce_AudioProcessorParameter.h
  31. +36
    -17
      source/modules/juce_audio_processors/scanning/juce_PluginListComponent.cpp
  32. +18
    -4
      source/modules/juce_audio_processors/scanning/juce_PluginListComponent.h
  33. +1
    -1
      source/modules/juce_core/containers/juce_AbstractFifo.h
  34. +2
    -2
      source/modules/juce_core/containers/juce_Array.h
  35. +22
    -9
      source/modules/juce_core/containers/juce_ReferenceCountedArray.h
  36. +1
    -1
      source/modules/juce_core/files/juce_FileInputStream.cpp
  37. +4
    -4
      source/modules/juce_core/files/juce_FileOutputStream.cpp
  38. +1
    -1
      source/modules/juce_core/javascript/juce_JSON.cpp
  39. +9
    -0
      source/modules/juce_core/javascript/juce_Javascript.cpp
  40. +5
    -0
      source/modules/juce_core/juce_core.cpp
  41. +49
    -10
      source/modules/juce_core/maths/juce_MathsFunctions.h
  42. +1
    -1
      source/modules/juce_core/memory/juce_ByteOrder.h
  43. +13
    -13
      source/modules/juce_core/memory/juce_HeapBlock.h
  44. +1
    -1
      source/modules/juce_core/memory/juce_MemoryBlock.cpp
  45. +1
    -1
      source/modules/juce_core/memory/juce_Singleton.h
  46. +30
    -2
      source/modules/juce_core/native/java/JuceAppActivity.java
  47. +2
    -2
      source/modules/juce_core/native/juce_linux_CommonFile.cpp
  48. +8
    -4
      source/modules/juce_core/native/juce_linux_Files.cpp
  49. +8
    -8
      source/modules/juce_core/native/juce_linux_Network.cpp
  50. +22
    -5
      source/modules/juce_core/native/juce_linux_SystemStats.cpp
  51. +0
    -22
      source/modules/juce_core/native/juce_linux_Threads.cpp
  52. +4
    -9
      source/modules/juce_core/native/juce_mac_Files.mm
  53. +8
    -4
      source/modules/juce_core/native/juce_mac_Network.mm
  54. +2
    -0
      source/modules/juce_core/native/juce_mac_SystemStats.mm
  55. +5
    -1
      source/modules/juce_core/native/juce_osx_ObjCHelpers.h
  56. +42
    -16
      source/modules/juce_core/native/juce_posix_SharedCode.h
  57. +10
    -2
      source/modules/juce_core/native/juce_win32_SystemStats.cpp
  58. +1
    -1
      source/modules/juce_core/network/juce_IPAddress.cpp
  59. +240
    -174
      source/modules/juce_core/network/juce_Socket.cpp
  60. +74
    -44
      source/modules/juce_core/network/juce_Socket.h
  61. +1
    -1
      source/modules/juce_core/streams/juce_MemoryOutputStream.h
  62. +6
    -3
      source/modules/juce_core/system/juce_SystemStats.cpp
  63. +28
    -24
      source/modules/juce_core/system/juce_SystemStats.h
  64. +1
    -1
      source/modules/juce_core/text/juce_CharPointer_UTF8.h
  65. +8
    -8
      source/modules/juce_core/text/juce_CharacterFunctions.cpp
  66. +6
    -9
      source/modules/juce_core/text/juce_Identifier.cpp
  67. +5
    -6
      source/modules/juce_core/text/juce_String.cpp
  68. +2
    -2
      source/modules/juce_core/text/juce_String.h
  69. +1
    -1
      source/modules/juce_core/threads/juce_Thread.h
  70. +1
    -1
      source/modules/juce_core/xml/juce_XmlElement.h
  71. +1
    -1
      source/modules/juce_core/zip/juce_GZIPCompressorOutputStream.h
  72. +23
    -12
      source/modules/juce_core/zip/juce_GZIPDecompressorInputStream.cpp
  73. +16
    -4
      source/modules/juce_core/zip/juce_GZIPDecompressorInputStream.h
  74. +3
    -1
      source/modules/juce_core/zip/juce_ZipFile.cpp
  75. +16
    -16
      source/modules/juce_core/zip/zlib/trees.c
  76. +1
    -1
      source/modules/juce_data_structures/app_properties/juce_PropertiesFile.h
  77. +8
    -0
      source/modules/juce_data_structures/undomanager/juce_UndoManager.cpp
  78. +5
    -0
      source/modules/juce_data_structures/undomanager/juce_UndoManager.h
  79. +2
    -2
      source/modules/juce_data_structures/values/juce_Value.cpp
  80. +15
    -5
      source/modules/juce_data_structures/values/juce_ValueTree.cpp
  81. +1
    -1
      source/modules/juce_events/messages/juce_ApplicationBase.cpp
  82. +1
    -2
      source/modules/juce_events/messages/juce_ApplicationBase.h
  83. +11
    -1
      source/modules/juce_events/native/juce_ios_MessageManager.mm
  84. +4
    -2
      source/modules/juce_events/native/juce_linux_Messaging.cpp
  85. +4
    -2
      source/modules/juce_events/native/juce_mac_MessageManager.mm
  86. +41
    -41
      source/modules/juce_events/timers/juce_Timer.cpp
  87. +8
    -10
      source/modules/juce_events/timers/juce_Timer.h
  88. +28
    -11
      source/modules/juce_graphics/colour/juce_Colour.cpp
  89. +13
    -0
      source/modules/juce_graphics/colour/juce_Colour.h
  90. +306
    -154
      source/modules/juce_graphics/colour/juce_PixelFormats.h
  91. +12
    -4
      source/modules/juce_graphics/contexts/juce_GraphicsContext.h
  92. +2
    -2
      source/modules/juce_graphics/contexts/juce_LowLevelGraphicsPostScriptRenderer.cpp
  93. +4
    -0
      source/modules/juce_graphics/fonts/juce_Font.cpp
  94. +12
    -0
      source/modules/juce_graphics/fonts/juce_Font.h
  95. +4
    -1
      source/modules/juce_graphics/fonts/juce_GlyphArrangement.cpp
  96. +5
    -1
      source/modules/juce_graphics/fonts/juce_GlyphArrangement.h
  97. +5
    -0
      source/modules/juce_graphics/fonts/juce_TextLayout.cpp
  98. +13
    -13
      source/modules/juce_graphics/geometry/juce_Line.h
  99. +5
    -5
      source/modules/juce_graphics/geometry/juce_Path.cpp
  100. +11
    -12
      source/modules/juce_graphics/geometry/juce_Path.h

+ 5
- 2
source/modules/juce_audio_basics/buffers/juce_AudioSampleBuffer.cpp View File

@@ -116,8 +116,11 @@ void AudioSampleBuffer::setDataToReferTo (float** dataToReferTo,
jassert (dataToReferTo != nullptr);
jassert (newNumChannels >= 0 && newNumSamples >= 0);
allocatedBytes = 0;
allocatedData.free();
if (allocatedBytes != 0)
{
allocatedBytes = 0;
allocatedData.free();
}
numChannels = newNumChannels;
size = newNumSamples;


+ 131
- 11
source/modules/juce_audio_basics/buffers/juce_FloatVectorOperations.cpp View File

@@ -49,8 +49,13 @@ namespace FloatVectorHelpers
{
typedef float Type;
typedef __m128 ParallelType;
typedef __m128 IntegerType;
enum { numParallel = 4 };
// Integer and parallel types are the same for SSE. On neon they have different types
static forcedinline IntegerType toint (ParallelType v) noexcept { return v; }
static forcedinline ParallelType toflt (IntegerType v) noexcept { return v; }
static forcedinline ParallelType load1 (Type v) noexcept { return _mm_load1_ps (&v); }
static forcedinline ParallelType loadA (const Type* v) noexcept { return _mm_load_ps (v); }
static forcedinline ParallelType loadU (const Type* v) noexcept { return _mm_loadu_ps (v); }
@@ -63,6 +68,11 @@ namespace FloatVectorHelpers
static forcedinline ParallelType max (ParallelType a, ParallelType b) noexcept { return _mm_max_ps (a, b); }
static forcedinline ParallelType min (ParallelType a, ParallelType b) noexcept { return _mm_min_ps (a, b); }
static forcedinline ParallelType bit_and (ParallelType a, ParallelType b) noexcept { return _mm_and_ps (a, b); }
static forcedinline ParallelType bit_not (ParallelType a, ParallelType b) noexcept { return _mm_andnot_ps (a, b); }
static forcedinline ParallelType bit_or (ParallelType a, ParallelType b) noexcept { return _mm_or_ps (a, b); }
static forcedinline ParallelType bit_xor (ParallelType a, ParallelType b) noexcept { return _mm_xor_ps (a, b); }
static forcedinline Type max (ParallelType a) noexcept { Type v[numParallel]; storeU (v, a); return jmax (v[0], v[1], v[2], v[3]); }
static forcedinline Type min (ParallelType a) noexcept { Type v[numParallel]; storeU (v, a); return jmin (v[0], v[1], v[2], v[3]); }
};
@@ -71,8 +81,13 @@ namespace FloatVectorHelpers
{
typedef double Type;
typedef __m128d ParallelType;
typedef __m128d IntegerType;
enum { numParallel = 2 };
// Integer and parallel types are the same for SSE. On neon they have different types
static forcedinline IntegerType toint (ParallelType v) noexcept { return v; }
static forcedinline ParallelType toflt (IntegerType v) noexcept { return v; }
static forcedinline ParallelType load1 (Type v) noexcept { return _mm_load1_pd (&v); }
static forcedinline ParallelType loadA (const Type* v) noexcept { return _mm_load_pd (v); }
static forcedinline ParallelType loadU (const Type* v) noexcept { return _mm_loadu_pd (v); }
@@ -85,10 +100,17 @@ namespace FloatVectorHelpers
static forcedinline ParallelType max (ParallelType a, ParallelType b) noexcept { return _mm_max_pd (a, b); }
static forcedinline ParallelType min (ParallelType a, ParallelType b) noexcept { return _mm_min_pd (a, b); }
static forcedinline ParallelType bit_and (ParallelType a, ParallelType b) noexcept { return _mm_and_pd (a, b); }
static forcedinline ParallelType bit_not (ParallelType a, ParallelType b) noexcept { return _mm_andnot_pd (a, b); }
static forcedinline ParallelType bit_or (ParallelType a, ParallelType b) noexcept { return _mm_or_pd (a, b); }
static forcedinline ParallelType bit_xor (ParallelType a, ParallelType b) noexcept { return _mm_xor_pd (a, b); }
static forcedinline Type max (ParallelType a) noexcept { Type v[numParallel]; storeU (v, a); return jmax (v[0], v[1]); }
static forcedinline Type min (ParallelType a) noexcept { Type v[numParallel]; storeU (v, a); return jmin (v[0], v[1]); }
};
#define JUCE_BEGIN_VEC_OP \
typedef FloatVectorHelpers::ModeType<sizeof(*dest)>::Mode Mode; \
if (FloatVectorHelpers::isSSE2Available()) \
@@ -126,23 +148,62 @@ namespace FloatVectorHelpers
#define JUCE_PERFORM_VEC_OP_SRC1_SRC2_DEST(normalOp, vecOp, locals, increment, setupOp) \
JUCE_BEGIN_VEC_OP \
setupOp \
if (FloatVectorHelpers::isAligned (dest)) \
{ \
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); \
if (FloatVectorHelpers::isAligned (src1)) \
{ \
if (FloatVectorHelpers::isAligned (src2)) JUCE_VEC_LOOP_TWO_SOURCES (vecOp, Mode::loadA, Mode::loadA, Mode::storeA, locals, increment) \
else JUCE_VEC_LOOP_TWO_SOURCES (vecOp, Mode::loadA, Mode::loadU, Mode::storeA, locals, increment) \
} \
else \
{ \
if (FloatVectorHelpers::isAligned (src2)) JUCE_VEC_LOOP_TWO_SOURCES (vecOp, Mode::loadU, Mode::loadA, Mode::storeA, locals, increment) \
else JUCE_VEC_LOOP_TWO_SOURCES (vecOp, Mode::loadU, Mode::loadU, Mode::storeA, locals, increment) \
} \
} \
else \
{ \
if (FloatVectorHelpers::isAligned (src1)) \
{ \
if (FloatVectorHelpers::isAligned (src2)) JUCE_VEC_LOOP_TWO_SOURCES (vecOp, Mode::loadA, Mode::loadA, Mode::storeU, locals, increment) \
else JUCE_VEC_LOOP_TWO_SOURCES (vecOp, Mode::loadA, Mode::loadU, Mode::storeU, locals, increment) \
} \
else \
{ \
if (FloatVectorHelpers::isAligned (src2)) JUCE_VEC_LOOP_TWO_SOURCES (vecOp, Mode::loadU, Mode::loadA, Mode::storeU, locals, increment) \
else JUCE_VEC_LOOP_TWO_SOURCES (vecOp, Mode::loadU, Mode::loadU, Mode::storeU, locals, increment) \
} \
} \
JUCE_FINISH_VEC_OP (normalOp)
#define JUCE_PERFORM_VEC_OP_SRC1_SRC2_DEST_DEST(normalOp, vecOp, locals, increment, setupOp) \
JUCE_BEGIN_VEC_OP \
setupOp \
if (FloatVectorHelpers::isAligned (dest)) \
{ \
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; \
Mode::ParallelType (&loadDst) (const Mode::Type* v) = FloatVectorHelpers::isAligned (dest) ? Mode::loadA : Mode::loadU; \
void (&storeDst) (Mode::Type* dest, Mode::ParallelType a) = FloatVectorHelpers::isAligned (dest) ? Mode::storeA : Mode::storeU; \
JUCE_VEC_LOOP_TWO_SOURCES_WITH_DEST_LOAD (vecOp, loadSrc1, loadSrc2, loadDst, storeDst, locals, increment); \
if (FloatVectorHelpers::isAligned (src1)) \
{ \
if (FloatVectorHelpers::isAligned (src2)) JUCE_VEC_LOOP_TWO_SOURCES_WITH_DEST_LOAD (vecOp, Mode::loadA, Mode::loadA, Mode::loadA, Mode::storeA, locals, increment) \
else JUCE_VEC_LOOP_TWO_SOURCES_WITH_DEST_LOAD (vecOp, Mode::loadA, Mode::loadU, Mode::loadA, Mode::storeA, locals, increment) \
} \
else \
{ \
if (FloatVectorHelpers::isAligned (src2)) JUCE_VEC_LOOP_TWO_SOURCES_WITH_DEST_LOAD (vecOp, Mode::loadU, Mode::loadA, Mode::loadA, Mode::storeA, locals, increment) \
else JUCE_VEC_LOOP_TWO_SOURCES_WITH_DEST_LOAD (vecOp, Mode::loadU, Mode::loadU, Mode::loadA, Mode::storeA, locals, increment) \
} \
} \
else \
{ \
if (FloatVectorHelpers::isAligned (src1)) \
{ \
if (FloatVectorHelpers::isAligned (src2)) JUCE_VEC_LOOP_TWO_SOURCES_WITH_DEST_LOAD (vecOp, Mode::loadA, Mode::loadA, Mode::loadU, Mode::storeU, locals, increment) \
else JUCE_VEC_LOOP_TWO_SOURCES_WITH_DEST_LOAD (vecOp, Mode::loadA, Mode::loadU, Mode::loadU, Mode::storeU, locals, increment) \
} \
else \
{ \
if (FloatVectorHelpers::isAligned (src2)) JUCE_VEC_LOOP_TWO_SOURCES_WITH_DEST_LOAD (vecOp, Mode::loadU, Mode::loadA, Mode::loadU, Mode::storeU, locals, increment) \
else JUCE_VEC_LOOP_TWO_SOURCES_WITH_DEST_LOAD (vecOp, Mode::loadU, Mode::loadU, Mode::loadU, Mode::storeU, locals, increment) \
} \
} \
JUCE_FINISH_VEC_OP (normalOp)
@@ -154,8 +215,12 @@ namespace FloatVectorHelpers
{
typedef float Type;
typedef float32x4_t ParallelType;
typedef uint32x4_t IntegerType;
enum { numParallel = 4 };
static forcedinline IntegerType toint (ParallelType v) noexcept { union { ParallelType f; IntegerType i; } u; u.f = v; return u.i; }
static forcedinline ParallelType toflt (IntegerType v) noexcept { union { ParallelType f; IntegerType i; } u; u.i = v; return u.f; }
static forcedinline ParallelType load1 (Type v) noexcept { return vld1q_dup_f32 (&v); }
static forcedinline ParallelType loadA (const Type* v) noexcept { return vld1q_f32 (v); }
static forcedinline ParallelType loadU (const Type* v) noexcept { return vld1q_f32 (v); }
@@ -168,6 +233,11 @@ namespace FloatVectorHelpers
static forcedinline ParallelType max (ParallelType a, ParallelType b) noexcept { return vmaxq_f32 (a, b); }
static forcedinline ParallelType min (ParallelType a, ParallelType b) noexcept { return vminq_f32 (a, b); }
static forcedinline ParallelType bit_and (ParallelType a, ParallelType b) noexcept { return toflt (vandq_u32 (toint (a), toint (b))); }
static forcedinline ParallelType bit_not (ParallelType a, ParallelType b) noexcept { return toflt (vbicq_u32 (toint (a), toint (b))); }
static forcedinline ParallelType bit_or (ParallelType a, ParallelType b) noexcept { return toflt (vorrq_u32 (toint (a), toint (b))); }
static forcedinline ParallelType bit_xor (ParallelType a, ParallelType b) noexcept { return toflt (veorq_u32 (toint (a), toint (b))); }
static forcedinline Type max (ParallelType a) noexcept { Type v[numParallel]; storeU (v, a); return jmax (v[0], v[1], v[2], v[3]); }
static forcedinline Type min (ParallelType a) noexcept { Type v[numParallel]; storeU (v, a); return jmin (v[0], v[1], v[2], v[3]); }
};
@@ -176,8 +246,12 @@ namespace FloatVectorHelpers
{
typedef double Type;
typedef double ParallelType;
typedef uint64 IntegerType;
enum { numParallel = 1 };
static forcedinline IntegerType toint (ParallelType v) noexcept { union { ParallelType f; IntegerType i; } u; u.f = v; return u.i; }
static forcedinline ParallelType toflt (IntegerType v) noexcept { union { ParallelType f; IntegerType i; } u; u.i = v; return u.f; }
static forcedinline ParallelType load1 (Type v) noexcept { return v; }
static forcedinline ParallelType loadA (const Type* v) noexcept { return *v; }
static forcedinline ParallelType loadU (const Type* v) noexcept { return *v; }
@@ -190,6 +264,11 @@ namespace FloatVectorHelpers
static forcedinline ParallelType max (ParallelType a, ParallelType b) noexcept { return jmax (a, b); }
static forcedinline ParallelType min (ParallelType a, ParallelType b) noexcept { return jmin (a, b); }
static forcedinline ParallelType bit_and (ParallelType a, ParallelType b) noexcept { return toflt (toint (a) & toint (b)); }
static forcedinline ParallelType bit_not (ParallelType a, ParallelType b) noexcept { return toflt ((~toint (a)) & toint (b)); }
static forcedinline ParallelType bit_or (ParallelType a, ParallelType b) noexcept { return toflt (toint (a) | toint (b)); }
static forcedinline ParallelType bit_xor (ParallelType a, ParallelType b) noexcept { return toflt (toint (a) ^ toint (b)); }
static forcedinline Type max (ParallelType a) noexcept { return a; }
static forcedinline Type min (ParallelType a) noexcept { return a; }
};
@@ -428,7 +507,7 @@ void JUCE_CALLTYPE FloatVectorOperations::clear (float* dest, int num) noexcept
#if JUCE_USE_VDSP_FRAMEWORK
vDSP_vclr (dest, 1, (size_t) num);
#else
zeromem (dest, num * sizeof (float));
zeromem (dest, (size_t) num * sizeof (float));
#endif
}
@@ -437,7 +516,7 @@ void JUCE_CALLTYPE FloatVectorOperations::clear (double* dest, int num) noexcept
#if JUCE_USE_VDSP_FRAMEWORK
vDSP_vclrD (dest, 1, (size_t) num);
#else
zeromem (dest, num * sizeof (double));
zeromem (dest, (size_t) num * sizeof (double));
#endif
}
@@ -495,8 +574,12 @@ void JUCE_CALLTYPE FloatVectorOperations::copyWithMultiply (double* dest, const
void JUCE_CALLTYPE FloatVectorOperations::add (float* dest, float amount, int num) noexcept
{
#if JUCE_USE_VDSP_FRAMEWORK
vDSP_vsadd (dest, 1, &amount, dest, 1, (vDSP_Length) num);
#else
JUCE_PERFORM_VEC_OP_DEST (dest[i] += amount, Mode::add (d, amountToAdd), JUCE_LOAD_DEST,
const Mode::ParallelType amountToAdd = Mode::load1 (amount);)
#endif
}
void JUCE_CALLTYPE FloatVectorOperations::add (double* dest, double amount, int num) noexcept
@@ -601,9 +684,13 @@ void JUCE_CALLTYPE FloatVectorOperations::subtract (double* dest, const double*
void JUCE_CALLTYPE FloatVectorOperations::addWithMultiply (float* dest, const float* src, float multiplier, int num) noexcept
{
#if JUCE_USE_VDSP_FRAMEWORK
vDSP_vsma (src, 1, &multiplier, dest, 1, dest, 1, (vDSP_Length) num);
#else
JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] += src[i] * multiplier, Mode::add (d, Mode::mul (mult, s)),
JUCE_LOAD_SRC_DEST, JUCE_INCREMENT_SRC_DEST,
const Mode::ParallelType mult = Mode::load1 (multiplier);)
#endif
}
void JUCE_CALLTYPE FloatVectorOperations::addWithMultiply (double* dest, const double* src, double multiplier, int num) noexcept
@@ -723,6 +810,33 @@ void FloatVectorOperations::negate (double* dest, const double* src, int num) no
#endif
}
void FloatVectorOperations::abs (float* dest, const float* src, int num) noexcept
{
#if JUCE_USE_VDSP_FRAMEWORK
vDSP_vabs ((float*) src, 1, dest, 1, (vDSP_Length) num);
#else
union {float f; uint32 i;} signMask;
signMask.i = 0x7fffffffUL;
JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] = fabsf (src[i]), Mode::bit_and (s, mask),
JUCE_LOAD_SRC, JUCE_INCREMENT_SRC_DEST,
const Mode::ParallelType mask = Mode::load1 (signMask.f);)
#endif
}
void FloatVectorOperations::abs (double* dest, const double* src, int num) noexcept
{
#if JUCE_USE_VDSP_FRAMEWORK
vDSP_vabsD ((double*) src, 1, dest, 1, (vDSP_Length) num);
#else
union {double d; uint64 i;} signMask;
signMask.i = 0x7fffffffffffffffULL;
JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] = fabs (src[i]), Mode::bit_and (s, mask),
JUCE_LOAD_SRC, JUCE_INCREMENT_SRC_DEST,
const Mode::ParallelType mask = Mode::load1 (signMask.d);)
#endif
}
void JUCE_CALLTYPE FloatVectorOperations::convertFixedToFloat (float* dest, const int* src, float multiplier, int num) noexcept
{
#if JUCE_USE_ARM_NEON
@@ -966,6 +1080,12 @@ public:
FloatVectorOperations::subtract (data1, data2, num);
u.expect (areAllValuesEqual (data1, num, (ValueType) 512));
FloatVectorOperations::abs (data1, data2, num);
u.expect (areAllValuesEqual (data1, num, (ValueType) 256));
FloatVectorOperations::abs (data2, data1, num);
u.expect (areAllValuesEqual (data2, num, (ValueType) 256));
fillRandomly (random, int1, num);
doConversionTest (u, data1, data2, int1, num);


+ 6
- 0
source/modules/juce_audio_basics/buffers/juce_FloatVectorOperations.h View File

@@ -137,6 +137,12 @@ public:
/** Copies a source vector to a destination, negating each value. */
static void JUCE_CALLTYPE negate (double* dest, const double* src, int numValues) noexcept;
/** Copies a source vector to a destination, taking the absolute of each value. */
static void JUCE_CALLTYPE abs (float* dest, const float* src, int numValues) noexcept;
/** Copies a source vector to a destination, taking the absolute of each value. */
static void JUCE_CALLTYPE abs (double* dest, const double* src, int numValues) noexcept;
/** Converts a stream of integers to floats, multiplying each one by the given multiplier. */
static void JUCE_CALLTYPE convertFixedToFloat (float* dest, const int* src, float multiplier, int numValues) noexcept;


+ 1
- 1
source/modules/juce_audio_basics/effects/juce_Reverb.h View File

@@ -333,7 +333,7 @@ private:
if (countdown <= 0)
currentValue = target;
else
step = (target - currentValue) / countdown;
step = (target - currentValue) / (float) countdown;
}
}


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

@@ -66,6 +66,9 @@
#if __ARM_NEON__ && ! (JUCE_USE_VDSP_FRAMEWORK || defined (JUCE_USE_ARM_NEON))
#define JUCE_USE_ARM_NEON 1
#endif
#if JUCE_USE_ARM_NEON
#include <arm_neon.h>
#endif


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

@@ -145,7 +145,7 @@ void MidiKeyboardState::processNextMidiBuffer (MidiBuffer& buffer,
const bool injectIndirectEvents)
{
MidiBuffer::Iterator i (buffer);
MidiMessage message (0xf4, 0.0);
MidiMessage message;
int time;
const ScopedLock sl (lock);


+ 96
- 26
source/modules/juce_audio_basics/synthesisers/juce_Synthesiser.cpp View File

@@ -63,6 +63,7 @@ void SynthesiserVoice::clearCurrentNote()
}
void SynthesiserVoice::aftertouchChanged (int) {}
void SynthesiserVoice::channelPressureChanged (int) {}
bool SynthesiserVoice::wasStartedBefore (const SynthesiserVoice& other) const noexcept
{
@@ -73,6 +74,7 @@ bool SynthesiserVoice::wasStartedBefore (const SynthesiserVoice& other) const no
Synthesiser::Synthesiser()
: sampleRate (0),
lastNoteOnCounter (0),
minimumSubBlockSize (32),
shouldStealNotes (true)
{
for (int i = 0; i < numElementsInArray (lastPitchWheelValues); ++i)
@@ -131,6 +133,12 @@ void Synthesiser::setNoteStealingEnabled (const bool shouldSteal)
shouldStealNotes = shouldSteal;
}
void Synthesiser::setMinimumRenderingSubdivisionSize (int numSamples) noexcept
{
jassert (numSamples > 0); // it wouldn't make much sense for this to be less than 1
minimumSubBlockSize = numSamples;
}
//==============================================================================
void Synthesiser::setCurrentPlaybackSampleRate (const double newRate)
{
@@ -153,30 +161,45 @@ void Synthesiser::renderNextBlock (AudioSampleBuffer& outputBuffer, const MidiBu
// must set the sample rate before using this!
jassert (sampleRate != 0);
const ScopedLock sl (lock);
MidiBuffer::Iterator midiIterator (midiData);
midiIterator.setNextSamplePosition (startSample);
MidiMessage m (0xf4, 0.0);
int midiEventPos;
MidiMessage m;
const ScopedLock sl (lock);
while (numSamples > 0)
{
int midiEventPos;
const bool useEvent = midiIterator.getNextEvent (m, midiEventPos)
&& midiEventPos < startSample + numSamples;
if (! midiIterator.getNextEvent (m, midiEventPos))
{
renderVoices (outputBuffer, startSample, numSamples);
return;
}
const int numThisTime = useEvent ? midiEventPos - startSample
: numSamples;
const int samplesToNextMidiMessage = midiEventPos - startSample;
if (numThisTime > 0)
renderVoices (outputBuffer, startSample, numThisTime);
if (samplesToNextMidiMessage >= numSamples)
{
renderVoices (outputBuffer, startSample, numSamples);
handleMidiEvent (m);
break;
}
if (useEvent)
if (samplesToNextMidiMessage < minimumSubBlockSize)
{
handleMidiEvent (m);
continue;
}
startSample += numThisTime;
numSamples -= numThisTime;
renderVoices (outputBuffer, startSample, samplesToNextMidiMessage);
handleMidiEvent (m);
startSample += samplesToNextMidiMessage;
numSamples -= samplesToNextMidiMessage;
}
while (midiIterator.getNextEvent (m, midiEventPos))
handleMidiEvent (m);
}
void Synthesiser::renderVoices (AudioSampleBuffer& buffer, int startSample, int numSamples)
@@ -187,33 +210,41 @@ void Synthesiser::renderVoices (AudioSampleBuffer& buffer, int startSample, int
void Synthesiser::handleMidiEvent (const MidiMessage& m)
{
const int channel = m.getChannel();
if (m.isNoteOn())
{
noteOn (m.getChannel(), m.getNoteNumber(), m.getFloatVelocity());
noteOn (channel, m.getNoteNumber(), m.getFloatVelocity());
}
else if (m.isNoteOff())
{
noteOff (m.getChannel(), m.getNoteNumber(), m.getFloatVelocity(), true);
noteOff (channel, m.getNoteNumber(), m.getFloatVelocity(), true);
}
else if (m.isAllNotesOff() || m.isAllSoundOff())
{
allNotesOff (m.getChannel(), true);
allNotesOff (channel, true);
}
else if (m.isPitchWheel())
{
const int channel = m.getChannel();
const int wheelPos = m.getPitchWheelValue();
lastPitchWheelValues [channel - 1] = wheelPos;
handlePitchWheel (channel, wheelPos);
}
else if (m.isAftertouch())
{
handleAftertouch (m.getChannel(), m.getNoteNumber(), m.getAfterTouchValue());
handleAftertouch (channel, m.getNoteNumber(), m.getAfterTouchValue());
}
else if (m.isChannelPressure())
{
handleChannelPressure (channel, m.getChannelPressureValue());
}
else if (m.isController())
{
handleController (m.getChannel(), m.getControllerNumber(), m.getControllerValue());
handleController (channel, m.getControllerNumber(), m.getControllerValue());
}
else if (m.isProgramChange())
{
handleProgramChange (channel, m.getProgramChangeNumber());
}
}
@@ -375,6 +406,19 @@ void Synthesiser::handleAftertouch (int midiChannel, int midiNoteNumber, int aft
}
}
void Synthesiser::handleChannelPressure (int midiChannel, int channelPressureValue)
{
const ScopedLock sl (lock);
for (int i = voices.size(); --i >= 0;)
{
SynthesiserVoice* const voice = voices.getUnchecked (i);
if (midiChannel <= 0 || voice->isPlayingChannel (midiChannel))
voice->channelPressureChanged (channelPressureValue);
}
}
void Synthesiser::handleSustainPedal (int midiChannel, bool isDown)
{
jassert (midiChannel > 0 && midiChannel <= 16);
@@ -423,6 +467,12 @@ void Synthesiser::handleSoftPedal (int midiChannel, bool /*isDown*/)
jassert (midiChannel > 0 && midiChannel <= 16);
}
void Synthesiser::handleProgramChange (int midiChannel, int programNumber)
{
(void) midiChannel; (void) programNumber;
jassert (midiChannel > 0 && midiChannel <= 16);
}
//==============================================================================
SynthesiserVoice* Synthesiser::findFreeVoice (SynthesiserSound* soundToPlay,
int midiChannel, int midiNoteNumber,
@@ -481,10 +531,10 @@ SynthesiserVoice* Synthesiser::findVoiceToSteal (SynthesiserSound* soundToPlay,
}
}
const int stealableVoiceRange = usableVoices.size() - 6;
const int numUsableVoices = usableVoices.size();
// The oldest note that's playing with the target pitch playing is ideal..
for (int i = 0; i < stealableVoiceRange; ++i)
for (int i = 0; i < numUsableVoices; ++i)
{
SynthesiserVoice* const voice = usableVoices.getUnchecked (i);
@@ -492,8 +542,27 @@ SynthesiserVoice* Synthesiser::findVoiceToSteal (SynthesiserSound* soundToPlay,
return voice;
}
// ..otherwise, look for the oldest note that isn't the top or bottom note..
for (int i = 0; i < stealableVoiceRange; ++i)
// Oldest voice that has been released (no finger on it and not held by sustain pedal)
for (int i = 0; i < numUsableVoices; ++i)
{
SynthesiserVoice* const voice = usableVoices.getUnchecked (i);
if (voice != bottom && voice != top && ! voice->isKeyDown() && ! voice->isSostenutoPedalDown())
return voice;
}
// Oldest voice that doesn't have a finger on it:
for (int i = 0; i < numUsableVoices; ++i)
{
SynthesiserVoice* const voice = usableVoices.getUnchecked (i);
if (voice != bottom && voice != top && ! voice->isKeyDown())
return voice;
}
// At this point, all notes have fingers on them, so look for the oldest note
// that isn't the top or bottom note..
for (int i = 0; i < numUsableVoices; ++i)
{
SynthesiserVoice* const voice = usableVoices.getUnchecked (i);
@@ -501,6 +570,7 @@ SynthesiserVoice* Synthesiser::findVoiceToSteal (SynthesiserSound* soundToPlay,
return voice;
}
// ..otherwise, there's only one or two voices to choose from - we'll return the oldest one..
return usableVoices.getFirst();
// ..otherwise, there's only one or two voices to choose from - prefer to steal the highest one:
jassert (top != nullptr || bottom != nullptr);
return (top == nullptr ? bottom : top);
}

+ 43
- 0
source/modules/juce_audio_basics/synthesisers/juce_Synthesiser.h View File

@@ -161,6 +161,11 @@ public:
*/
virtual void aftertouchChanged (int newAftertouchValue);
/** Called to let the voice know that the channel pressure has changed.
This will be called during the rendering callback, so must be fast and thread-safe.
*/
virtual void channelPressureChanged (int newChannelPressureValue);
//==============================================================================
/** Renders the next block of data for this voice.
@@ -440,6 +445,20 @@ public:
*/
virtual void handleAftertouch (int midiChannel, int midiNoteNumber, int aftertouchValue);
/** Sends a channel pressure message.
This will send a channel pressure message to any voices that are playing sounds on
the given midi channel.
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 channelPressureValue the pressure value, between 0 and 127, as returned
by MidiMessage::getChannelPressureValue()
*/
virtual void handleChannelPressure (int midiChannel, int channelPressureValue);
/** Handles a sustain pedal event. */
virtual void handleSustainPedal (int midiChannel, bool isDown);
@@ -449,6 +468,13 @@ public:
/** Can be overridden to handle soft pedal events. */
virtual void handleSoftPedal (int midiChannel, bool isDown);
/** Can be overridden to handle an incoming program change message.
The base class implementation of this has no effect, but you may want to make your
own synth react to program changes.
*/
virtual void handleProgramChange (int midiChannel,
int programNumber);
//==============================================================================
/** Tells the synthesiser what the sample rate is for the audio it's being used to render.
@@ -479,6 +505,22 @@ public:
*/
double getSampleRate() const noexcept { return sampleRate; }
/** Sets a minimum limit on the size to which audio sub-blocks will be divided when rendering.
When rendering, the audio blocks that are passed into renderNextBlock() will be split up
into smaller blocks that lie between all the incoming midi messages, and it is these smaller
sub-blocks that are rendered with multiple calls to renderVoices().
Obviously in a pathological case where there are midi messages on every sample, then
renderVoices() could be called once per sample and lead to poor performance, so this
setting allows you to set a lower limit on the block size.
The default setting is 32, which means that midi messages are accurate to about < 1ms
accuracy, which is probably fine for most purposes, but you may want to increase or
decrease this value for your synth.
*/
void setMinimumRenderingSubdivisionSize (int numSamples) noexcept;
protected:
//==============================================================================
/** This is used to control access to the rendering callback and the note trigger methods. */
@@ -537,6 +579,7 @@ private:
//==============================================================================
double sampleRate;
uint32 lastNoteOnCounter;
int minimumSubBlockSize;
bool shouldStealNotes;
BigInteger sustainPedalsDown;


+ 5
- 0
source/modules/juce_audio_devices/audio_io/juce_AudioDeviceManager.cpp View File

@@ -551,6 +551,11 @@ double AudioDeviceManager::chooseBestSampleRate (double rate) const
const Array<double> rates (currentAudioDevice->getAvailableSampleRates());
if (rate > 0 && rates.contains (rate))
return rate;
rate = currentAudioDevice->getCurrentSampleRate();
if (rate > 0 && rates.contains (rate))
return rate;


+ 21
- 21
source/modules/juce_audio_devices/native/juce_linux_ALSA.cpp View File

@@ -57,7 +57,7 @@ static void getDeviceSampleRates (snd_pcm_t* handle, Array<double>& rates)
for (int i = 0; ratesToTry[i] != 0; ++i)
{
if (snd_pcm_hw_params_any (handle, hwParams) >= 0
&& snd_pcm_hw_params_test_rate (handle, hwParams, ratesToTry[i], 0) == 0)
&& snd_pcm_hw_params_test_rate (handle, hwParams, (unsigned int) ratesToTry[i], 0) == 0)
{
rates.addIfNotAlreadyThere ((double) ratesToTry[i]);
}
@@ -257,10 +257,10 @@ public:
int dir = 0;
unsigned int periods = 4;
snd_pcm_uframes_t samplesPerPeriod = bufferSize;
snd_pcm_uframes_t samplesPerPeriod = (snd_pcm_uframes_t) bufferSize;
if (JUCE_ALSA_FAILED (snd_pcm_hw_params_set_rate_near (handle, hwParams, &sampleRate, 0))
|| JUCE_ALSA_FAILED (snd_pcm_hw_params_set_channels (handle, hwParams, numChannels))
|| JUCE_ALSA_FAILED (snd_pcm_hw_params_set_channels (handle, hwParams, (unsigned int ) numChannels))
|| JUCE_ALSA_FAILED (snd_pcm_hw_params_set_periods_near (handle, hwParams, &periods, &dir))
|| JUCE_ALSA_FAILED (snd_pcm_hw_params_set_period_size_near (handle, hwParams, &samplesPerPeriod, &dir))
|| JUCE_ALSA_FAILED (snd_pcm_hw_params (handle, hwParams)))
@@ -274,7 +274,7 @@ public:
|| JUCE_ALSA_FAILED (snd_pcm_hw_params_get_periods (hwParams, &periods, &dir)))
latency = 0;
else
latency = frames * (periods - 1); // (this is the method JACK uses to guess the latency..)
latency = (int) frames * ((int) periods - 1); // (this is the method JACK uses to guess the latency..)
JUCE_ALSA_LOG ("frames: " << (int) frames << ", periods: " << (int) periods
<< ", samplesPerPeriod: " << (int) samplesPerPeriod);
@@ -316,22 +316,22 @@ public:
if (isInterleaved)
{
scratch.ensureSize (sizeof (float) * numSamples * numChannelsRunning, false);
scratch.ensureSize ((size_t) ((int) sizeof (float) * numSamples * numChannelsRunning), false);
for (int i = 0; i < numChannelsRunning; ++i)
converter->convertSamples (scratch.getData(), i, data[i], 0, numSamples);
numDone = snd_pcm_writei (handle, scratch.getData(), numSamples);
numDone = snd_pcm_writei (handle, scratch.getData(), (snd_pcm_uframes_t) numSamples);
}
else
{
for (int i = 0; i < numChannelsRunning; ++i)
converter->convertSamples (data[i], data[i], numSamples);
numDone = snd_pcm_writen (handle, (void**) data, numSamples);
numDone = snd_pcm_writen (handle, (void**) data, (snd_pcm_uframes_t) numSamples);
}
if (numDone < 0 && JUCE_ALSA_FAILED (snd_pcm_recover (handle, numDone, 1 /* silent */)))
if (numDone < 0 && JUCE_ALSA_FAILED (snd_pcm_recover (handle, (int) numDone, 1 /* silent */)))
return false;
if (numDone < numSamples)
@@ -347,12 +347,12 @@ public:
if (isInterleaved)
{
scratch.ensureSize (sizeof (float) * numSamples * numChannelsRunning, false);
scratch.ensureSize ((size_t) ((int) sizeof (float) * numSamples * numChannelsRunning), false);
scratch.fillWith (0); // (not clearing this data causes warnings in valgrind)
snd_pcm_sframes_t num = snd_pcm_readi (handle, scratch.getData(), numSamples);
snd_pcm_sframes_t num = snd_pcm_readi (handle, scratch.getData(), (snd_pcm_uframes_t) numSamples);
if (num < 0 && JUCE_ALSA_FAILED (snd_pcm_recover (handle, num, 1 /* silent */)))
if (num < 0 && JUCE_ALSA_FAILED (snd_pcm_recover (handle, (int) num, 1 /* silent */)))
return false;
if (num < numSamples)
@@ -363,9 +363,9 @@ public:
}
else
{
snd_pcm_sframes_t num = snd_pcm_readn (handle, (void**) data, numSamples);
snd_pcm_sframes_t num = snd_pcm_readn (handle, (void**) data, (snd_pcm_uframes_t) numSamples);
if (num < 0 && JUCE_ALSA_FAILED (snd_pcm_recover (handle, num, 1 /* silent */)))
if (num < 0 && JUCE_ALSA_FAILED (snd_pcm_recover (handle, (int) num, 1 /* silent */)))
return false;
if (num < numSamples)
@@ -503,7 +503,7 @@ public:
}
}
ensureMinimumNumBitsSet (outputChannels, minChansOut);
ensureMinimumNumBitsSet (outputChannels, (int) minChansOut);
outputChannelBuffer.setSize (jmax ((int) minChansOut, outputChannels.getHighestBit()) + 1, bufferSize);
outputChannelBuffer.clear();
@@ -557,7 +557,7 @@ public:
return;
}
ensureMinimumNumBitsSet (currentInputChans, minChansIn);
ensureMinimumNumBitsSet (currentInputChans, (int) minChansIn);
if (! inputDevice->setParameters ((unsigned int) sampleRate,
jlimit ((int) minChansIn, (int) maxChansIn, currentInputChans.getHighestBit() + 1),
@@ -656,7 +656,7 @@ public:
snd_pcm_sframes_t avail = snd_pcm_avail_update (inputDevice->handle);
if (avail < 0)
JUCE_ALSA_FAILED (snd_pcm_recover (inputDevice->handle, avail, 0));
JUCE_ALSA_FAILED (snd_pcm_recover (inputDevice->handle, (int) avail, 0));
}
audioIoInProgress = true;
@@ -688,7 +688,7 @@ public:
else
{
for (int i = 0; i < outputChannelDataForCallback.size(); ++i)
zeromem (outputChannelDataForCallback[i], sizeof (float) * bufferSize);
zeromem (outputChannelDataForCallback[i], sizeof (float) * (size_t) bufferSize);
}
}
@@ -702,7 +702,7 @@ public:
snd_pcm_sframes_t avail = snd_pcm_avail_update (outputDevice->handle);
if (avail < 0)
JUCE_ALSA_FAILED (snd_pcm_recover (outputDevice->handle, avail, 0));
JUCE_ALSA_FAILED (snd_pcm_recover (outputDevice->handle, (int) avail, 0));
audioIoInProgress = true;
@@ -1092,9 +1092,9 @@ private:
if (snd_ctl_pcm_next_device (handle, &device) < 0 || device < 0)
break;
snd_pcm_info_set_device (pcmInfo, device);
snd_pcm_info_set_device (pcmInfo, (unsigned int) device);
for (int subDevice = 0, nbSubDevice = 1; subDevice < nbSubDevice; ++subDevice)
for (unsigned int subDevice = 0, nbSubDevice = 1; subDevice < nbSubDevice; ++subDevice)
{
snd_pcm_info_set_subdevice (pcmInfo, subDevice);
snd_pcm_info_set_stream (pcmInfo, SND_PCM_STREAM_CAPTURE);
@@ -1118,7 +1118,7 @@ private:
}
else
{
id << "hw:" << cardId << "," << device << "," << subDevice;
id << "hw:" << cardId << "," << device << "," << (int) subDevice;
name << cardName << ", " << snd_pcm_info_get_name (pcmInfo)
<< " {" << snd_pcm_info_get_subdevice_name (pcmInfo) << "}";
}


+ 7
- 7
source/modules/juce_audio_devices/native/juce_linux_Midi.cpp View File

@@ -133,14 +133,14 @@ private:
if (snd_midi_event_new (maxEventSize, &midiParser) >= 0)
{
const int numPfds = snd_seq_poll_descriptors_count (seqHandle, POLLIN);
HeapBlock<pollfd> pfd (numPfds);
snd_seq_poll_descriptors (seqHandle, pfd, numPfds, POLLIN);
HeapBlock<pollfd> pfd ((size_t) numPfds);
snd_seq_poll_descriptors (seqHandle, pfd, (unsigned int) numPfds, POLLIN);
HeapBlock <uint8> buffer (maxEventSize);
while (! threadShouldExit())
{
if (poll (pfd, numPfds, 100) > 0) // there was a "500" here which is a bit long when we exit the program and have to wait for a timeout on this poll call
if (poll (pfd, (nfds_t) numPfds, 100) > 0) // there was a "500" here which is a bit long when we exit the program and have to wait for a timeout on this poll call
{
if (threadShouldExit())
break;
@@ -154,14 +154,14 @@ private:
if (snd_seq_event_input (seqHandle, &inputEvent) >= 0)
{
// xxx what about SYSEXes that are too big for the buffer?
const int numBytes = snd_midi_event_decode (midiParser, buffer,
const long numBytes = snd_midi_event_decode (midiParser, buffer,
maxEventSize, inputEvent);
snd_midi_event_reset_decode (midiParser);
if (numBytes > 0)
{
const MidiMessage message ((const uint8*) buffer, numBytes,
const MidiMessage message ((const uint8*) buffer, (int) numBytes,
Time::getMillisecondCounter() * 0.001);
client.handleIncomingMidiMessage (message, inputEvent->dest.port);
@@ -410,7 +410,7 @@ public:
maxEventSize (16 * 1024)
{
jassert (port.isValid() && midiOutput != nullptr);
snd_midi_event_new (maxEventSize, &midiParser);
snd_midi_event_new ((size_t) maxEventSize, &midiParser);
}
~MidiOutputDevice()
@@ -425,7 +425,7 @@ public:
{
maxEventSize = message.getRawDataSize();
snd_midi_event_free (midiParser);
snd_midi_event_new (maxEventSize, &midiParser);
snd_midi_event_new ((size_t) maxEventSize, &midiParser);
}
snd_seq_event_t event;


+ 6
- 0
source/modules/juce_audio_devices/native/juce_mac_CoreAudio.cpp View File

@@ -1067,6 +1067,12 @@ public:
jassert (! isOpen());
jassert (! device->isOpen());
devices.add (new DeviceWrapper (*this, device, useInputs, useOutputs));
if (currentSampleRate == 0)
currentSampleRate = device->getCurrentSampleRate();
if (currentBufferSize == 0)
currentBufferSize = device->getCurrentBufferSizeSamples();
}
Array<AudioIODevice*> getDevices() const


+ 7
- 5
source/modules/juce_audio_devices/native/juce_win32_ASIO.cpp View File

@@ -1416,13 +1416,15 @@ private:
}
};
template <>
struct ASIOCallbackFunctions <sizeof(currentASIODev) / sizeof(currentASIODev[0])>
{
static void setCallbacksForDevice (ASIOCallbacks&, ASIOAudioIODevice*) noexcept {}
};
void setCallbackFunctions() noexcept
{
/**/ if (currentASIODev[0] == this) ASIOCallbackFunctions<0>::setCallbacks (callbacks);
else if (currentASIODev[1] == this) ASIOCallbackFunctions<1>::setCallbacks (callbacks);
else if (currentASIODev[2] == this) ASIOCallbackFunctions<2>::setCallbacks (callbacks);
else if (currentASIODev[3] == this) ASIOCallbackFunctions<3>::setCallbacks (callbacks);
else jassertfalse;
ASIOCallbackFunctions<0>::setCallbacksForDevice (callbacks, this);
}
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ASIOAudioIODevice)


+ 2
- 2
source/modules/juce_audio_formats/codecs/juce_LAMEEncoderAudioFormat.cpp View File

@@ -30,9 +30,9 @@ public:
Writer (OutputStream* destStream, const String& formatName,
const File& appFile, int vbr, int cbr,
double sampleRate, unsigned int numberOfChannels,
unsigned int bitsPerSample, const StringPairArray& metadata)
int bitsPerSample, const StringPairArray& metadata)
: AudioFormatWriter (destStream, formatName, sampleRate,
numberOfChannels, bitsPerSample),
numberOfChannels, (unsigned int) bitsPerSample),
vbrLevel (vbr), cbrBitrate (cbr),
tempWav (".wav")
{


+ 2
- 3
source/modules/juce_audio_formats/codecs/juce_MP3AudioFormat.cpp View File

@@ -426,9 +426,8 @@ struct VBRTagData
if (flags & 4)
{
if (toc != nullptr)
for (int i = 0; i < 100; ++i)
toc[i] = data[i];
for (int i = 0; i < 100; ++i)
toc[i] = data[i];
data += 100;
}


+ 5
- 5
source/modules/juce_audio_formats/codecs/juce_QuickTimeAudioFormat.cpp View File

@@ -194,7 +194,7 @@ public:
bufferList->mNumberBuffers = 1;
bufferList->mBuffers[0].mNumberChannels = inputStreamDesc.mChannelsPerFrame;
bufferList->mBuffers[0].mDataByteSize = jmax ((UInt32) 4096, (UInt32) (samplesPerFrame * inputStreamDesc.mBytesPerFrame) + 16);
bufferList->mBuffers[0].mDataByteSize = jmax ((UInt32) 4096, (UInt32) (samplesPerFrame * (int) inputStreamDesc.mBytesPerFrame) + 16);
dataBuffer.malloc (bufferList->mBuffers[0].mDataByteSize);
bufferList->mBuffers[0].mData = dataBuffer;
@@ -262,10 +262,10 @@ public:
}
int framesToDo = jmin (numSamples, (int) (bufferList->mBuffers[0].mDataByteSize / inputStreamDesc.mBytesPerFrame));
bufferList->mBuffers[0].mDataByteSize = inputStreamDesc.mBytesPerFrame * framesToDo;
bufferList->mBuffers[0].mDataByteSize = inputStreamDesc.mBytesPerFrame * (UInt32) framesToDo;
UInt32 outFlags = 0;
UInt32 actualNumFrames = framesToDo;
UInt32 actualNumFrames = (UInt32) framesToDo;
OSStatus err = MovieAudioExtractionFillBuffer (extractor, &actualNumFrames, bufferList, &outFlags);
if (err != noErr)
{
@@ -274,7 +274,7 @@ public:
}
lastSampleRead = startSampleInFile + actualNumFrames;
const int samplesReceived = actualNumFrames;
const int samplesReceived = (int) actualNumFrames;
for (int j = numDestChannels; --j >= 0;)
{
@@ -298,7 +298,7 @@ public:
{
for (int j = numDestChannels; --j >= 0;)
if (destSamples[j] != nullptr)
zeromem (destSamples[j] + startOffsetInDestBuffer, sizeof (int) * numSamples);
zeromem (destSamples[j] + startOffsetInDestBuffer, sizeof (int) * (size_t) numSamples);
break;
}


+ 7
- 5
source/modules/juce_audio_formats/codecs/juce_WavAudioFormat.cpp View File

@@ -609,16 +609,18 @@ namespace WavFileHelpers
{
static MemoryBlock createFrom (const StringPairArray& values)
{
const String s = values[WavAudioFormat::tracktionLoopInfo];
MemoryBlock data;
MemoryOutputStream out;
const String s (values[WavAudioFormat::tracktionLoopInfo]);
if (s.isNotEmpty())
{
MemoryOutputStream os (data, false);
os.writeString (s);
out.writeString (s);
if ((out.getDataSize() & 1) != 0)
out.writeByte (0);
}
return data;
return out.getMemoryBlock();
}
};


+ 1
- 1
source/modules/juce_audio_formats/codecs/oggvorbis/libvorbis-1.3.2/lib/floor1.c View File

@@ -850,7 +850,7 @@ int floor1_encode(oggpack_buffer *opb,vorbis_block *vb,
/* generate the partition's first stage cascade value */
if(csubbits){
int maxval[8];
int maxval[8] = { 0 };
for(k=0;k<csub;k++){
int booknum=info->class_subbook[classx][k];
if(booknum<0){


+ 1
- 1
source/modules/juce_audio_formats/format/juce_AudioFormat.h View File

@@ -119,7 +119,7 @@ public:
should then be deleted by the caller.
If the stream can't be created for some reason (e.g. the parameters passed in
here aren't suitable), this will return 0.
here aren't suitable), this will return nullptr.
@param streamToWriteTo the stream that the data will go to - this will be
deleted by the AudioFormatWriter object when it's no longer


+ 2
- 2
source/modules/juce_audio_formats/format/juce_AudioFormatReaderSource.h View File

@@ -58,10 +58,10 @@ public:
@see isLooping
*/
void setLooping (bool shouldLoop);
void setLooping (bool shouldLoop) override;
/** Returns whether loop-mode is turned on or not. */
bool isLooping() const { return looping; }
bool isLooping() const override { return looping; }
/** Returns the reader that's being used. */
AudioFormatReader* getAudioFormatReader() const noexcept { return reader; }


+ 1
- 1
source/modules/juce_audio_formats/sampler/juce_Sampler.h View File

@@ -126,7 +126,7 @@ public:
void startNote (int midiNoteNumber, float velocity, SynthesiserSound*, int pitchWheel) override;
void stopNote (float velocity, bool allowTailOff) override;
void pitchWheelMoved (int newValue);
void pitchWheelMoved (int newValue) override;
void controllerMoved (int controllerNumber, int newValue) override;
void renderNextBlock (AudioSampleBuffer&, int startSample, int numSamples) override;


+ 40
- 40
source/modules/juce_audio_processors/format_types/juce_AudioUnitPluginFormat.mm View File

@@ -184,7 +184,7 @@ namespace AudioUnitFormatHelpers
const char* const utf8 = fileOrIdentifier.toUTF8();
if (CFURLRef url = CFURLCreateFromFileSystemRepresentation (0, (const UInt8*) utf8,
strlen (utf8), file.isDirectory()))
(CFIndex) strlen (utf8), file.isDirectory()))
{
CFBundleRef bundleRef = CFBundleCreate (kCFAllocatorDefault, url);
CFRelease (url);
@@ -345,8 +345,8 @@ public:
refreshParameterList();
updateNumChannels();
producesMidiMessages = canProduceMidiOutput();
setPlayConfigDetails (numInputBusChannels * numInputBusses,
numOutputBusChannels * numOutputBusses,
setPlayConfigDetails ((int) (numInputBusChannels * numInputBusses),
(int) (numOutputBusChannels * numOutputBusses),
rate, blockSize);
setLatencySamples (0);
@@ -420,7 +420,7 @@ public:
UInt32 sampleRateSize = sizeof (sampleRateIn);
const Float64 sr = newSampleRate;
for (int i = 0; i < numInputBusses; ++i)
for (AudioUnitElement i = 0; i < numInputBusses; ++i)
{
AudioUnitGetProperty (audioUnit, kAudioUnitProperty_SampleRate, kAudioUnitScope_Input, i, &sampleRateIn, &sampleRateSize);
@@ -428,7 +428,7 @@ public:
AudioUnitSetProperty (audioUnit, kAudioUnitProperty_SampleRate, kAudioUnitScope_Input, i, &sr, sizeof (sr));
}
for (int i = 0; i < numOutputBusses; ++i)
for (AudioUnitElement i = 0; i < numOutputBusses; ++i)
{
AudioUnitGetProperty (audioUnit, kAudioUnitProperty_SampleRate, kAudioUnitScope_Output, i, &sampleRateOut, &sampleRateSize);
@@ -440,9 +440,9 @@ public:
AudioUnitSetProperty (audioUnit, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 0,
&frameSize, sizeof (frameSize));
setPlayConfigDetails (numInputBusChannels * numInputBusses,
numOutputBusChannels * numOutputBusses,
newSampleRate, estimatedSamplesPerBlock);
setPlayConfigDetails ((int) (numInputBusChannels * numInputBusses),
(int) (numOutputBusChannels * numOutputBusses),
(double) newSampleRate, estimatedSamplesPerBlock);
Float64 latencySecs = 0.0;
UInt32 latencySize = sizeof (latencySecs);
@@ -463,13 +463,13 @@ public:
stream.mBitsPerChannel = 32;
stream.mChannelsPerFrame = numInputBusChannels;
for (int i = 0; i < numInputBusses; ++i)
for (AudioUnitElement i = 0; i < numInputBusses; ++i)
AudioUnitSetProperty (audioUnit, kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Input, i, &stream, sizeof (stream));
stream.mChannelsPerFrame = numOutputBusChannels;
for (int i = 0; i < numOutputBusses; ++i)
for (AudioUnitElement i = 0; i < numOutputBusses; ++i)
AudioUnitSetProperty (audioUnit, kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Output, i, &stream, sizeof (stream));
}
@@ -518,8 +518,8 @@ public:
void resetBusses()
{
for (int i = 0; i < numInputBusses; ++i) AudioUnitReset (audioUnit, kAudioUnitScope_Input, i);
for (int i = 0; i < numOutputBusses; ++i) AudioUnitReset (audioUnit, kAudioUnitScope_Output, i);
for (AudioUnitElement i = 0; i < numInputBusses; ++i) AudioUnitReset (audioUnit, kAudioUnitScope_Input, i);
for (AudioUnitElement i = 0; i < numOutputBusses; ++i) AudioUnitReset (audioUnit, kAudioUnitScope_Output, i);
}
void processBlock (AudioSampleBuffer& buffer, MidiBuffer& midiMessages) override
@@ -530,17 +530,17 @@ public:
{
timeStamp.mHostTime = AudioGetCurrentHostTime();
for (int i = 0; i < numOutputBusses; ++i)
for (AudioUnitElement i = 0; i < numOutputBusses; ++i)
{
if (AudioBufferList* const abl = getAudioBufferListForBus(i))
{
abl->mNumberBuffers = numOutputBusChannels;
for (int j = 0; j < numOutputBusChannels; ++j)
for (AudioUnitElement j = 0; j < numOutputBusChannels; ++j)
{
abl->mBuffers[j].mNumberChannels = 1;
abl->mBuffers[j].mDataByteSize = sizeof (float) * numSamples;
abl->mBuffers[j].mData = buffer.getWritePointer (i * numOutputBusChannels + j);
abl->mBuffers[j].mDataByteSize = sizeof (float) * (size_t) numSamples;
abl->mBuffers[j].mData = buffer.getWritePointer ((int) (i * numOutputBusChannels + j));
}
}
}
@@ -557,19 +557,19 @@ public:
if (midiEventSize <= 3)
MusicDeviceMIDIEvent (audioUnit,
midiEventData[0], midiEventData[1], midiEventData[2],
midiEventPosition);
(UInt32) midiEventPosition);
else
MusicDeviceSysEx (audioUnit, midiEventData, midiEventSize);
MusicDeviceSysEx (audioUnit, midiEventData, (UInt32) midiEventSize);
}
midiMessages.clear();
}
for (int i = 0; i < numOutputBusses; ++i)
for (AudioUnitElement i = 0; i < numOutputBusses; ++i)
{
AudioUnitRenderActionFlags flags = 0;
AudioUnitRender (audioUnit, &flags, &timeStamp, i, numSamples, getAudioBufferListForBus (i));
AudioUnitRender (audioUnit, &flags, &timeStamp, i, (UInt32) numSamples, getAudioBufferListForBus (i));
}
timeStamp.mSampleTime += numSamples;
@@ -796,7 +796,7 @@ public:
CFDataRef data = (CFDataRef) CFWriteStreamCopyProperty (stream, kCFStreamPropertyDataWritten);
destData.setSize (bytesWritten);
destData.setSize ((size_t) bytesWritten);
destData.copyFrom (CFDataGetBytePtr (data), 0, destData.getSize());
CFRelease (data);
@@ -911,7 +911,7 @@ private:
HeapBlock <AudioBufferList> outputBufferList;
AudioTimeStamp timeStamp;
AudioSampleBuffer* currentBuffer;
int numInputBusChannels, numOutputBusChannels, numInputBusses, numOutputBusses;
AudioUnitElement numInputBusChannels, numOutputBusChannels, numInputBusses, numOutputBusses;
AudioUnit audioUnit;
AUEventListenerRef eventListenerRef;
@@ -941,7 +941,7 @@ private:
info.inputProcRefCon = this;
info.inputProc = renderGetInputCallback;
for (int i = 0; i < numInputBusses; ++i)
for (AudioUnitElement i = 0; i < numInputBusses; ++i)
AudioUnitSetProperty (audioUnit, kAudioUnitProperty_SetRenderCallback,
kAudioUnitScope_Input, i, &info, sizeof (info));
}
@@ -1028,11 +1028,11 @@ private:
break;
case kAudioUnitEvent_BeginParameterChangeGesture:
beginParameterChangeGesture (event.mArgument.mParameter.mParameterID);
beginParameterChangeGesture ((int) event.mArgument.mParameter.mParameterID);
break;
case kAudioUnitEvent_EndParameterChangeGesture:
endParameterChangeGesture (event.mArgument.mParameter.mParameterID);
endParameterChangeGesture ((int) event.mArgument.mParameter.mParameterID);
break;
default:
@@ -1062,7 +1062,7 @@ private:
for (UInt32 i = 0; i < ioData->mNumberBuffers; ++i)
{
const int bufferChannel = inBusNumber * numInputBusChannels + i;
const int bufferChannel = (int) (inBusNumber * numInputBusChannels + i);
if (bufferChannel < currentBuffer->getNumChannels())
{
@@ -1131,16 +1131,16 @@ private:
if (ph != nullptr && ph->getCurrentPosition (result))
{
setIfNotNull (outTimeSig_Numerator, result.timeSigNumerator);
setIfNotNull (outTimeSig_Denominator, result.timeSigDenominator);
setIfNotNull (outDeltaSampleOffsetToNextBeat, 0); //xxx
setIfNotNull (outTimeSig_Numerator, (UInt32) result.timeSigNumerator);
setIfNotNull (outTimeSig_Denominator, (UInt32) result.timeSigDenominator);
setIfNotNull (outDeltaSampleOffsetToNextBeat, (UInt32) 0); //xxx
setIfNotNull (outCurrentMeasureDownBeat, result.ppqPositionOfLastBarStart); //xxx wrong
}
else
{
setIfNotNull (outDeltaSampleOffsetToNextBeat, 0);
setIfNotNull (outTimeSig_Numerator, 4);
setIfNotNull (outTimeSig_Denominator, 4);
setIfNotNull (outDeltaSampleOffsetToNextBeat, (UInt32) 0);
setIfNotNull (outTimeSig_Numerator, (UInt32) 4);
setIfNotNull (outTimeSig_Denominator, (UInt32) 4);
setIfNotNull (outCurrentMeasureDownBeat, 0);
}
@@ -1226,12 +1226,12 @@ private:
return offsetof (AudioBufferList, mBuffers) + (sizeof (AudioBuffer) * numOutputBusChannels);
}
AudioBufferList* getAudioBufferListForBus (int busIndex) const noexcept
AudioBufferList* getAudioBufferListForBus (AudioUnitElement busIndex) const noexcept
{
return addBytesToPointer (outputBufferList.getData(), getAudioBufferSizeInBytes() * busIndex);
}
int getElementCount (AudioUnitScope scope) const noexcept
AudioUnitElement getElementCount (AudioUnitScope scope) const noexcept
{
UInt32 count;
UInt32 countSize = sizeof (count);
@@ -1240,7 +1240,7 @@ private:
|| countSize == 0)
count = 1;
return (int) count;
return count;
}
void updateNumChannels()
@@ -1266,17 +1266,17 @@ private:
const int outChannels = (int) supportedChannels[i].outChannels;
if (inChannels < 0)
maximumNumIns = jmin (maximumNumIns, inChannels);
maximumNumIns = jmin (maximumNumIns, inChannels);
else
explicitNumIns = jmax (explicitNumIns, inChannels);
if (outChannels < 0)
maximumNumOuts = jmin (maximumNumOuts, outChannels);
maximumNumOuts = jmin (maximumNumOuts, outChannels);
else
explicitNumOuts = jmax (explicitNumOuts, outChannels);
}
if ((maximumNumIns == -1 && maximumNumOuts == -1) // (special meaning: any number of ins/outs, as long as they match)
if ((maximumNumIns == -1 && maximumNumOuts == -1) // (special meaning: any number of ins/outs, as long as they match)
|| (maximumNumIns == -2 && maximumNumOuts == -1) // (special meaning: any number of ins/outs, even if they don't match)
|| (maximumNumIns == -1 && maximumNumOuts == -2))
{
@@ -1284,8 +1284,8 @@ private:
}
else
{
numInputBusChannels = explicitNumIns;
numOutputBusChannels = explicitNumOuts;
numInputBusChannels = (AudioUnitElement) explicitNumIns;
numOutputBusChannels = (AudioUnitElement) explicitNumOuts;
if (maximumNumIns == -1 || (maximumNumIns < 0 && explicitNumIns <= -maximumNumIns))
numInputBusChannels = 2;


+ 1
- 1
source/modules/juce_audio_processors/format_types/juce_LADSPAPluginFormat.cpp View File

@@ -26,7 +26,7 @@
} // (juce namespace)
#include <ladspa.h>
#include "ladspa.h"
namespace juce
{


+ 2
- 2
source/modules/juce_audio_processors/format_types/juce_VST3Common.h View File

@@ -250,7 +250,7 @@ public:
break;
case Steinberg::Vst::Event::kDataEvent:
result.addEvent (MidiMessage::createSysExMessage (e.data.bytes, e.data.size),
result.addEvent (MidiMessage::createSysExMessage (e.data.bytes, (int) e.data.size),
e.sampleOffset);
break;
@@ -300,7 +300,7 @@ public:
{
e.type = Steinberg::Vst::Event::kDataEvent;
e.data.bytes = msg.getSysExData();
e.data.size = msg.getSysExDataSize();
e.data.size = (uint32) msg.getSysExDataSize();
e.data.type = Steinberg::Vst::DataEvent::kMidiSysEx;
}
else if (msg.isAftertouch())


+ 87
- 58
source/modules/juce_audio_processors/format_types/juce_VSTPluginFormat.cpp View File

@@ -488,7 +488,7 @@ public:
const char* const utf8 = file.getFullPathName().toRawUTF8();
if (CFURLRef url = CFURLCreateFromFileSystemRepresentation (0, (const UInt8*) utf8,
strlen (utf8), file.isDirectory()))
(CFIndex) strlen (utf8), file.isDirectory()))
{
bundleRef = CFBundleCreate (kCFAllocatorDefault, url);
CFRelease (url);
@@ -864,7 +864,7 @@ public:
wantsMidiMessages = dispatch (effCanDo, 0, 0, (void*) "receiveVstMidiEvent", 0) > 0;
#if JUCE_MAC && JUCE_SUPPORT_CARBON
usesCocoaNSView = (dispatch (effCanDo, 0, 0, (void*) "hasCockosViewAsConfig", 0) & 0xffff0000) == 0xbeef0000;
usesCocoaNSView = (dispatch (effCanDo, 0, 0, (void*) "hasCockosViewAsConfig", 0) & (int) 0xffff0000) == 0xbeef0000;
#endif
setLatencySamples (effect->initialDelay);
@@ -987,27 +987,28 @@ public:
if (AudioPlayHead* const playHead = getPlayHead())
{
AudioPlayHead::CurrentPositionInfo position;
playHead->getCurrentPosition (position);
vstHostTime.samplePos = (double) position.timeInSamples;
vstHostTime.tempo = position.bpm;
vstHostTime.timeSigNumerator = position.timeSigNumerator;
vstHostTime.timeSigDenominator = position.timeSigDenominator;
vstHostTime.ppqPos = position.ppqPosition;
vstHostTime.barStartPos = position.ppqPositionOfLastBarStart;
vstHostTime.flags |= kVstTempoValid | kVstTimeSigValid | kVstPpqPosValid | kVstBarsValid;
VstInt32 newTransportFlags = 0;
if (position.isPlaying) newTransportFlags |= kVstTransportPlaying;
if (position.isRecording) newTransportFlags |= kVstTransportRecording;
if (newTransportFlags != (vstHostTime.flags & (kVstTransportPlaying | kVstTransportRecording)))
vstHostTime.flags = (vstHostTime.flags & ~(kVstTransportPlaying | kVstTransportRecording)) | newTransportFlags | kVstTransportChanged;
else
vstHostTime.flags &= ~kVstTransportChanged;
switch (position.frameRate)
if (playHead->getCurrentPosition (position))
{
vstHostTime.samplePos = (double) position.timeInSamples;
vstHostTime.tempo = position.bpm;
vstHostTime.timeSigNumerator = position.timeSigNumerator;
vstHostTime.timeSigDenominator = position.timeSigDenominator;
vstHostTime.ppqPos = position.ppqPosition;
vstHostTime.barStartPos = position.ppqPositionOfLastBarStart;
vstHostTime.flags |= kVstTempoValid | kVstTimeSigValid | kVstPpqPosValid | kVstBarsValid;
VstInt32 newTransportFlags = 0;
if (position.isPlaying) newTransportFlags |= kVstTransportPlaying;
if (position.isRecording) newTransportFlags |= kVstTransportRecording;
if (newTransportFlags != (vstHostTime.flags & (kVstTransportPlaying | kVstTransportRecording)))
vstHostTime.flags = (vstHostTime.flags & ~(kVstTransportPlaying | kVstTransportRecording)) | newTransportFlags | kVstTransportChanged;
else
vstHostTime.flags &= ~kVstTransportChanged;
switch (position.frameRate)
{
case AudioPlayHead::fps24: setHostTimeFrameRate (0, 24.0, position.timeInSeconds); break;
case AudioPlayHead::fps25: setHostTimeFrameRate (1, 25.0, position.timeInSeconds); break;
case AudioPlayHead::fps2997: setHostTimeFrameRate (2, 29.97, position.timeInSeconds); break;
@@ -1015,17 +1016,18 @@ public:
case AudioPlayHead::fps2997drop: setHostTimeFrameRate (4, 29.97, position.timeInSeconds); break;
case AudioPlayHead::fps30drop: setHostTimeFrameRate (5, 29.97, position.timeInSeconds); break;
default: break;
}
}
if (position.isLooping)
{
vstHostTime.cycleStartPos = position.ppqLoopStart;
vstHostTime.cycleEndPos = position.ppqLoopEnd;
vstHostTime.flags |= (kVstCyclePosValid | kVstTransportCycleActive);
}
else
{
vstHostTime.flags &= ~(kVstCyclePosValid | kVstTransportCycleActive);
if (position.isLooping)
{
vstHostTime.cycleStartPos = position.ppqLoopStart;
vstHostTime.cycleEndPos = position.ppqLoopEnd;
vstHostTime.flags |= (kVstCyclePosValid | kVstTransportCycleActive);
}
else
{
vstHostTime.flags &= ~(kVstCyclePosValid | kVstTransportCycleActive);
}
}
}
@@ -1228,8 +1230,8 @@ public:
void getStateInformation (MemoryBlock& mb) override { saveToFXBFile (mb, true); }
void getCurrentProgramStateInformation (MemoryBlock& mb) override { saveToFXBFile (mb, false); }
void setStateInformation (const void* data, int size) override { loadFromFXBFile (data, size); }
void setCurrentProgramStateInformation (const void* data, int size) override { loadFromFXBFile (data, size); }
void setStateInformation (const void* data, int size) override { loadFromFXBFile (data, (size_t) size); }
void setCurrentProgramStateInformation (const void* data, int size) override { loadFromFXBFile (data, (size_t) size); }
//==============================================================================
void timerCallback() override
@@ -1282,7 +1284,12 @@ public:
case audioMasterSizeWindow:
if (AudioProcessorEditor* ed = getActiveEditor())
ed->setSize (index, (int) value);
{
#if JUCE_LINUX
const MessageManagerLock mmLock;
#endif
ed->setSize (index, (int) value);
}
return 1;
@@ -1356,6 +1363,7 @@ public:
"receiveVstEvents",
"receiveVstMidiEvent",
"supportShell",
"sizeWindow",
"shellCategory" };
for (int i = 0; i < numElementsInArray (canDos); ++i)
@@ -1449,7 +1457,7 @@ public:
{
const int oldProg = getCurrentProgram();
const int numParams = fxbSwap (((const fxProgram*) (set->programs))->numParams);
const int progLen = sizeof (fxProgram) + (numParams - 1) * sizeof (float);
const int progLen = (int) sizeof (fxProgram) + (numParams - 1) * (int) sizeof (float);
for (int i = 0; i < fxbSwap (set->numPrograms); ++i)
{
@@ -1496,7 +1504,7 @@ public:
// non-preset chunk
const fxChunkSet* const cset = (const fxChunkSet*) data;
if (fxbSwap (cset->chunkSize) + sizeof (fxChunkSet) - 8 > (unsigned int) dataSize)
if ((size_t) fxbSwap (cset->chunkSize) + sizeof (fxChunkSet) - 8 > (size_t) dataSize)
return false;
setChunkData (cset->chunk, fxbSwap (cset->chunkSize), false);
@@ -1506,7 +1514,7 @@ public:
// preset chunk
const fxProgramSet* const cset = (const fxProgramSet*) data;
if (fxbSwap (cset->chunkSize) + sizeof (fxProgramSet) - 8 > (unsigned int) dataSize)
if ((size_t) fxbSwap (cset->chunkSize) + sizeof (fxProgramSet) - 8 > (size_t) dataSize)
return false;
setChunkData (cset->chunk, fxbSwap (cset->chunkSize), true);
@@ -1571,8 +1579,8 @@ public:
{
if (isFXB)
{
const int progLen = sizeof (fxProgram) + (numParams - 1) * sizeof (float);
const int len = (sizeof (fxSet) - sizeof (fxProgram)) + progLen * jmax (1, numPrograms);
const int progLen = (int) sizeof (fxProgram) + (numParams - 1) * (int) sizeof (float);
const size_t len = (sizeof (fxSet) - sizeof (fxProgram)) + (size_t) (progLen * jmax (1, numPrograms));
dest.setSize (len, true);
fxSet* const set = (fxSet*) dest.getData();
@@ -1584,11 +1592,13 @@ public:
set->fxVersion = fxbSwap (getVersionNumber());
set->numPrograms = fxbSwap (numPrograms);
const int oldProgram = getCurrentProgram();
MemoryBlock oldSettings;
createTempParameterStore (oldSettings);
setParamsInProgramBlock ((fxProgram*) (((char*) (set->programs)) + oldProgram * progLen));
const int oldProgram = getCurrentProgram();
if (oldProgram >= 0)
setParamsInProgramBlock ((fxProgram*) (((char*) (set->programs)) + oldProgram * progLen));
for (int i = 0; i < numPrograms; ++i)
{
@@ -1599,14 +1609,14 @@ public:
}
}
setCurrentProgram (oldProgram);
if (oldProgram >= 0)
setCurrentProgram (oldProgram);
restoreFromTempParameterStore (oldSettings);
}
else
{
const int totalLen = sizeof (fxProgram) + (numParams - 1) * sizeof (float);
dest.setSize (totalLen, true);
dest.setSize (sizeof (fxProgram) + (size_t) ((numParams - 1) * (int) sizeof (float)), true);
setParamsInProgramBlock ((fxProgram*) dest.getData());
}
}
@@ -1621,7 +1631,7 @@ public:
if (usesChunks())
{
void* data = nullptr;
const VstIntPtr bytes = dispatch (effGetChunk, isPreset ? 1 : 0, 0, &data, 0.0f);
const size_t bytes = (size_t) dispatch (effGetChunk, isPreset ? 1 : 0, 0, &data, 0.0f);
if (data != nullptr && bytes <= maxSizeMB * 1024 * 1024)
{
@@ -1783,7 +1793,7 @@ private:
//==============================================================================
void createTempParameterStore (MemoryBlock& dest)
{
dest.setSize (64 + 4 * getNumParameters());
dest.setSize (64 + 4 * (size_t) getNumParameters());
dest.fillWith (0);
getCurrentProgramName().copyToUTF8 ((char*) dest.getData(), 63);
@@ -1821,21 +1831,21 @@ private:
String s;
if (v == 0 || (int) v == -1)
v = getVersionNumber();
v = (unsigned int) getVersionNumber();
if (v != 0)
{
int versionBits[32];
int n = 0;
for (int vv = v; vv != 0; vv /= 10)
for (unsigned int vv = v; vv != 0; vv /= 10)
versionBits [n++] = vv % 10;
if (n > 4) // if the number ends up silly, it's probably encoded as hex instead of decimal..
{
n = 0;
for (int vv = v; vv != 0; vv >>= 8)
for (unsigned int vv = v; vv != 0; vv >>= 8)
versionBits [n++] = vv & 255;
}
@@ -1968,9 +1978,13 @@ public:
#elif JUCE_LINUX
if (pluginWindow != 0)
{
XResizeWindow (display, pluginWindow, getWidth(), getHeight());
XMoveWindow (display, pluginWindow, pos.getX(), pos.getY());
XMoveResizeWindow (display, pluginWindow,
pos.getX(), pos.getY(),
(unsigned int) getWidth(),
(unsigned int) getHeight());
XMapRaised (display, pluginWindow);
XFlush (display);
}
#endif
@@ -2081,6 +2095,16 @@ public:
plugin.dispatch (effEditIdle, 0, 0, 0, 0);
reentrant = false;
}
#if JUCE_LINUX
if (pluginWindow == 0)
{
updatePluginWindowHandle();
if (pluginWindow != 0)
componentMovedOrResized (true, true);
}
#endif
}
}
@@ -2266,11 +2290,7 @@ private:
}
#elif JUCE_LINUX
pluginWindow = getChildWindow ((Window) getWindowHandle());
if (pluginWindow != 0)
pluginProc = (EventProcPtr) getPropertyFromXWindow (pluginWindow,
XInternAtom (display, "_XEventProc", False));
updatePluginWindowHandle();
int w = 250, h = 150;
@@ -2498,6 +2518,15 @@ private:
sendEventToChild (ev);
}
}
void updatePluginWindowHandle()
{
pluginWindow = getChildWindow ((Window) getWindowHandle());
if (pluginWindow != 0)
pluginProc = (EventProcPtr) getPropertyFromXWindow (pluginWindow,
XInternAtom (display, "_XEventProc", False));
}
#endif
//==============================================================================


+ 3
- 1
source/modules/juce_audio_processors/processors/juce_AudioPlayHead.h View File

@@ -128,7 +128,9 @@ public:
//==============================================================================
/** Fills-in the given structure with details about the transport's
position at the start of the current processing block.
position at the start of the current processing block. If this method returns
false then the current play head position is not available and the given
structure will be undefined.
You can ONLY call this from your processBlock() method! Calling it at other
times will produce undefined behaviour, as the host may not have any context


+ 4
- 4
source/modules/juce_audio_processors/processors/juce_AudioProcessor.cpp View File

@@ -50,7 +50,7 @@ AudioProcessor::~AudioProcessor()
jassert (activeEditor == nullptr);
#endif
#if JUCE_DEBUG
#if JUCE_DEBUG && ! JUCE_DISABLE_AUDIOPROCESSOR_BEGIN_END_GESTURE_CHECKING
// This will fail if you've called beginParameterChangeGesture() for one
// or more parameters without having made a corresponding call to endParameterChangeGesture...
jassert (changingParams.countNumberOfSetBits() == 0);
@@ -144,7 +144,7 @@ void AudioProcessor::beginParameterChangeGesture (int parameterIndex)
{
if (isPositiveAndBelow (parameterIndex, getNumParameters()))
{
#if JUCE_DEBUG
#if JUCE_DEBUG && ! JUCE_DISABLE_AUDIOPROCESSOR_BEGIN_END_GESTURE_CHECKING
// This means you've called beginParameterChangeGesture twice in succession without a matching
// call to endParameterChangeGesture. That might be fine in most hosts, but better to avoid doing it.
jassert (! changingParams [parameterIndex]);
@@ -165,9 +165,9 @@ void AudioProcessor::endParameterChangeGesture (int parameterIndex)
{
if (isPositiveAndBelow (parameterIndex, getNumParameters()))
{
#if JUCE_DEBUG
#if JUCE_DEBUG && ! JUCE_DISABLE_AUDIOPROCESSOR_BEGIN_END_GESTURE_CHECKING
// This means you've called endParameterChangeGesture without having previously called
// endParameterChangeGesture. That might be fine in most hosts, but better to keep the
// beginParameterChangeGesture. That might be fine in most hosts, but better to keep the
// calls matched correctly.
jassert (changingParams [parameterIndex]);
changingParams.clearBit (parameterIndex);


+ 57
- 5
source/modules/juce_audio_processors/processors/juce_AudioProcessor.h View File

@@ -384,10 +384,17 @@ public:
//==============================================================================
/** This must return the correct value immediately after the object has been
created, and mustn't change the number of parameters later.
NOTE! This method will eventually be deprecated! It's recommended that you use the
AudioProcessorParameter class instead to manage your parameters.
*/
virtual int getNumParameters();
/** Returns the name of a particular parameter. */
/** Returns the name of a particular parameter.
NOTE! This method will eventually be deprecated! It's recommended that you use the
AudioProcessorParameter class instead to manage your parameters.
*/
virtual const String getParameterName (int parameterIndex);
/** Called by the host to find out the value of one of the filter's parameters.
@@ -397,27 +404,39 @@ public:
This could be called quite frequently, so try to make your code efficient.
It's also likely to be called by non-UI threads, so the code in here should
be thread-aware.
NOTE! This method will eventually be deprecated! It's recommended that you use the
AudioProcessorParameter class instead to manage your parameters.
*/
virtual float getParameter (int parameterIndex);
/** Returns the value of a parameter as a text string. */
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
will look better in constrained spaces (e.g. the displays on hardware controller
devices or mixing desks) then you should implement this method.
If you don't override it, the default implementation will call getParameterText(int),
and truncate the result.
NOTE! This method will eventually be deprecated! It's recommended that you use
AudioProcessorParameter::getName() instead.
*/
virtual String getParameterName (int parameterIndex, int maximumStringLength);
/** Returns the value of a parameter as a text string.
NOTE! This method will eventually be deprecated! It's recommended that you use
AudioProcessorParameter::getText() instead.
*/
virtual const String getParameterText (int parameterIndex);
/** Returns the value of a parameter as a text string with a preferred maximum length.
If you want to provide customised short versions of your parameter values that
will look better in constrained spaces (e.g. the displays on hardware controller
devices or mixing desks) then you should implement this method.
If you don't override it, the default implementation will call getParameterText(int),
and truncate the result.
NOTE! This method will eventually be deprecated! It's recommended that you use
AudioProcessorParameter::getText() instead.
*/
virtual String getParameterText (int parameterIndex, int maximumStringLength);
@@ -426,10 +445,16 @@ public:
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.
NOTE! This method will eventually be deprecated! It's recommended that you use
AudioProcessorParameter::getNumSteps() instead.
*/
virtual int getParameterNumSteps (int parameterIndex);
/** Returns the default number of steps for a parameter.
NOTE! This method will eventually be deprecated! It's recommended that you use
AudioProcessorParameter::getNumSteps() instead.
@see getParameterNumSteps
*/
static int getDefaultNumParameterSteps() noexcept;
@@ -437,16 +462,25 @@ public:
/** 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.
NOTE! This method will eventually be deprecated! It's recommended that you use
AudioProcessorParameter::getDefaultValue() instead.
*/
virtual float getParameterDefaultValue (int parameterIndex);
/** Some plugin types may be able to return a label string for a
parameter's units.
NOTE! This method will eventually be deprecated! It's recommended that you use
AudioProcessorParameter::getLabel() instead.
*/
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).
NOTE! This method will eventually be deprecated! It's recommended that you use
AudioProcessorParameter::isOrientationInverted() instead.
*/
virtual bool isParameterOrientationInverted (int index) const;
@@ -462,6 +496,9 @@ public:
won't be able to automate your parameters properly.
The value passed will be between 0 and 1.0.
NOTE! This method will eventually be deprecated! It's recommended that you use
AudioProcessorParameter::setValue() instead.
*/
virtual void setParameter (int parameterIndex, float newValue);
@@ -474,11 +511,17 @@ public:
Note that to make sure the host correctly handles automation, you should call
the beginParameterChangeGesture() and endParameterChangeGesture() methods to
tell the host when the user has started and stopped changing the parameter.
NOTE! This method will eventually be deprecated! It's recommended that you use
AudioProcessorParameter::setValueNotifyingHost() instead.
*/
void setParameterNotifyingHost (int parameterIndex, float newValue);
/** Returns true if the host can automate this parameter.
By default, this returns true for all parameters.
NOTE! This method will eventually be deprecated! It's recommended that you use
AudioProcessorParameter::isAutomatable() instead.
*/
virtual bool isParameterAutomatable (int parameterIndex) const;
@@ -486,6 +529,9 @@ public:
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.
NOTE! This method will eventually be deprecated! It's recommended that you use
AudioProcessorParameter::isMetaParameter() instead.
*/
virtual bool isMetaParameter (int parameterIndex) const;
@@ -496,6 +542,9 @@ public:
it may use this information to help it record automation.
If you call this, it must be matched by a later call to endParameterChangeGesture().
NOTE! This method will eventually be deprecated! It's recommended that you use
AudioProcessorParameter::beginChangeGesture() instead.
*/
void beginParameterChangeGesture (int parameterIndex);
@@ -505,6 +554,9 @@ public:
it may use this information to help it record automation.
A call to this method must follow a call to beginParameterChangeGesture().
NOTE! This method will eventually be deprecated! It's recommended that you use
AudioProcessorParameter::endChangeGesture() instead.
*/
void endParameterChangeGesture (int parameterIndex);
@@ -693,7 +745,7 @@ private:
OwnedArray<AudioProcessorParameter> managedParameters;
AudioProcessorParameter* getParamChecked (int) const noexcept;
#if JUCE_DEBUG
#if JUCE_DEBUG && ! JUCE_DISABLE_AUDIOPROCESSOR_BEGIN_END_GESTURE_CHECKING
BigInteger changingParams;
#endif


+ 1
- 1
source/modules/juce_audio_processors/processors/juce_AudioProcessorGraph.h View File

@@ -308,7 +308,7 @@ public:
void fillInPluginDescription (PluginDescription&) const override;
void prepareToPlay (double sampleRate, int estimatedSamplesPerBlock) override;
void releaseResources() override;
void processBlock (AudioSampleBuffer&, MidiBuffer&);
void processBlock (AudioSampleBuffer&, MidiBuffer&) override;
const String getInputChannelName (int channelIndex) const override;
const String getOutputChannelName (int channelIndex) const override;


+ 1
- 1
source/modules/juce_audio_processors/processors/juce_AudioProcessorParameter.h View File

@@ -68,7 +68,7 @@ public:
/** Your filter can call this when it needs to change one of its parameters.
This could happen when the editor or some other internal operation changes
a parameter. This method will call the setParameter() method to change the
a parameter. This method will call the setValue() method to change the
value, and will then send a message to the host telling it about the change.
Note that to make sure the host correctly handles automation, you should call


+ 36
- 17
source/modules/juce_audio_processors/scanning/juce_PluginListComponent.cpp View File

@@ -85,7 +85,7 @@ public:
void deleteKeyPressed (int) override
{
owner.removeSelected();
owner.removeSelectedPlugins();
}
void sortOrderChanged (int newSortColumnId, bool isForwards) override
@@ -102,14 +102,6 @@ public:
}
}
static void removePluginItem (KnownPluginList& list, int index)
{
if (index < list.getNumTypes())
list.removeType (index);
else
list.removeFromBlacklist (list.getBlacklistedFiles() [index - list.getNumTypes()]);
}
static String getPluginDescription (const PluginDescription& desc)
{
StringArray items;
@@ -179,6 +171,12 @@ void PluginListComponent::setOptionsButtonText (const String& newText)
resized();
}
void PluginListComponent::setScanDialogText (const String& title, const String& content)
{
dialogTitle = title;
dialogText = content;
}
void PluginListComponent::setNumberOfThreadsForScanning (int num)
{
numThreads = num;
@@ -207,13 +205,24 @@ void PluginListComponent::updateList()
table.repaint();
}
void PluginListComponent::removeSelected()
void PluginListComponent::removeSelectedPlugins()
{
const SparseSet<int> selected (table.getSelectedRows());
for (int i = table.getNumRows(); --i >= 0;)
if (selected.contains (i))
TableModel::removePluginItem (list, i);
removePluginItem (i);
}
void PluginListComponent::setTableModel (TableListBoxModel* model)
{
table.setModel (nullptr);
tableModel = model;
table.setModel (tableModel);
table.getHeader().reSortTable();
table.updateContent();
table.repaint();
}
bool PluginListComponent::canShowSelectedFolder() const
@@ -238,6 +247,14 @@ void PluginListComponent::removeMissingPlugins()
list.removeType (i);
}
void PluginListComponent::removePluginItem (int index)
{
if (index < list.getNumTypes())
list.removeType (index);
else
list.removeFromBlacklist (list.getBlacklistedFiles() [index - list.getNumTypes()]);
}
void PluginListComponent::optionsMenuStaticCallback (int result, PluginListComponent* pluginList)
{
if (pluginList != nullptr)
@@ -250,7 +267,7 @@ void PluginListComponent::optionsMenuCallback (int result)
{
case 0: break;
case 1: list.clear(); break;
case 2: removeSelected(); break;
case 2: removeSelectedPlugins(); break;
case 3: showSelectedFolder(); break;
case 4: removeMissingPlugins(); break;
@@ -293,7 +310,7 @@ bool PluginListComponent::isInterestedInFileDrag (const StringArray& /*files*/)
void PluginListComponent::filesDropped (const StringArray& files, int, int)
{
OwnedArray <PluginDescription> typesFound;
OwnedArray<PluginDescription> typesFound;
list.scanAndAddDragAndDroppedFiles (formatManager, files, typesFound);
}
@@ -313,11 +330,11 @@ void PluginListComponent::setLastSearchPath (PropertiesFile& properties, AudioPl
class PluginListComponent::Scanner : private Timer
{
public:
Scanner (PluginListComponent& plc, AudioPluginFormat& format, PropertiesFile* properties, int threads)
Scanner (PluginListComponent& plc, AudioPluginFormat& format, PropertiesFile* properties,
int threads, const String& title, const String& text)
: owner (plc), formatToScan (format), propertiesToUse (properties),
pathChooserWindow (TRANS("Select folders to scan..."), String::empty, AlertWindow::NoIcon),
progressWindow (TRANS("Scanning for plug-ins..."),
TRANS("Searching for all possible plug-in files..."), AlertWindow::NoIcon),
progressWindow (title, text, AlertWindow::NoIcon),
progress (0.0), numThreads (threads), finished (false)
{
FileSearchPath path (formatToScan.getDefaultLocationsToSearch());
@@ -528,7 +545,9 @@ private:
void PluginListComponent::scanFor (AudioPluginFormat& format)
{
currentScanner = new Scanner (*this, format, propertiesToUse, numThreads);
currentScanner = new Scanner (*this, format, propertiesToUse, numThreads,
dialogTitle.isNotEmpty() ? dialogTitle : TRANS("Scanning for plug-ins..."),
dialogText.isNotEmpty() ? dialogText : TRANS("Searching for all possible plug-in files..."));
}
bool PluginListComponent::isScanning() const noexcept


+ 18
- 4
source/modules/juce_audio_processors/scanning/juce_PluginListComponent.h View File

@@ -55,6 +55,10 @@ public:
/** Changes the text in the panel's options button. */
void setOptionsButtonText (const String& newText);
/** Changes the text in the progress dialog box that is shown when scanning. */
void setScanDialogText (const String& textForProgressWindowTitle,
const String& textForProgressWindowDescription);
/** Sets how many threads to simultaneously scan for plugins.
If this is 0, then all scanning happens on the message thread (this is the default)
*/
@@ -72,6 +76,17 @@ public:
/** Returns true if there's currently a scan in progress. */
bool isScanning() const noexcept;
/** Removes the plugins currently selected in the table. */
void removeSelectedPlugins();
/** Sets a custom table model to be used.
This will take ownership of the model and delete it when no longer needed.
*/
void setTableModel (TableListBoxModel* model);
/** Returns the table used to display the plugin list. */
TableListBox& getTableListBox() noexcept { return table; }
private:
//==============================================================================
AudioPluginFormatManager& formatManager;
@@ -80,12 +95,11 @@ private:
TableListBox table;
TextButton optionsButton;
PropertiesFile* propertiesToUse;
String dialogTitle, dialogText;
int numThreads;
class TableModel;
friend class TableModel;
friend struct ContainerDeletePolicy<TableModel>;
ScopedPointer<TableModel> tableModel;
ScopedPointer<TableListBoxModel> tableModel;
class Scanner;
friend class Scanner;
@@ -98,8 +112,8 @@ private:
void updateList();
void showSelectedFolder();
bool canShowSelectedFolder() const;
void removeSelected();
void removeMissingPlugins();
void removePluginItem (int index);
void resized() override;
bool isInterestedInFileDrag (const StringArray&) override;


+ 1
- 1
source/modules/juce_core/containers/juce_AbstractFifo.h View File

@@ -69,7 +69,7 @@
void readFromFifo (int* someData, int numItems)
{
int start1, size1, start2, size2;
abstractFifo.prepareToRead (numSamples, start1, size1, start2, size2);
abstractFifo.prepareToRead (numItems, start1, size1, start2, size2);
if (size1 > 0)
copySomeData (someData, myBuffer + start1, size1);


+ 2
- 2
source/modules/juce_core/containers/juce_Array.h View File

@@ -832,8 +832,8 @@ public:
/** Removes an item from the array.
This will remove the first occurrence of the given element from the array.
If the item isn't found, no action is taken.
This will remove all occurrences of the given element from the array.
If no such items are found, no action is taken.
@param valueToRemove the object to try to remove
@see remove, removeRange


+ 22
- 9
source/modules/juce_core/containers/juce_ReferenceCountedArray.h View File

@@ -119,26 +119,30 @@ public:
*/
~ReferenceCountedArray()
{
clear();
releaseAllObjects();
}
//==============================================================================
/** Removes all objects from the array.
Any objects in the array that are not referenced from elsewhere will be deleted.
Any objects in the array that whose reference counts drop to zero will be deleted.
*/
void clear()
{
const ScopedLockType lock (getLock());
while (numUsed > 0)
if (ObjectClass* o = data.elements [--numUsed])
releaseObject (o);
jassert (numUsed == 0);
releaseAllObjects();
data.setAllocatedSize (0);
}
/** Removes all objects from the array without freeing the array's allocated storage.
Any objects in the array that whose reference counts drop to zero will be deleted.
@see clear
*/
void clearQuick()
{
const ScopedLockType lock (getLock());
releaseAllObjects();
}
/** Returns the current number of objects in the array. */
inline int size() const noexcept
{
@@ -886,6 +890,15 @@ private:
ArrayAllocationBase <ObjectClass*, TypeOfCriticalSectionToUse> data;
int numUsed;
void releaseAllObjects()
{
while (numUsed > 0)
if (ObjectClass* o = data.elements [--numUsed])
releaseObject (o);
jassert (numUsed == 0);
}
static void releaseObject (ObjectClass* o)
{
if (o->decReferenceCountWithoutDeleting())


+ 1
- 1
source/modules/juce_core/files/juce_FileInputStream.cpp View File

@@ -57,7 +57,7 @@ int FileInputStream::read (void* buffer, int bytesToRead)
jassert (buffer != nullptr && bytesToRead >= 0);
const size_t num = readInternal (buffer, (size_t) bytesToRead);
currentPosition += num;
currentPosition += (int64) num;
return (int) num;
}


+ 4
- 4
source/modules/juce_core/files/juce_FileOutputStream.cpp View File

@@ -90,7 +90,7 @@ bool FileOutputStream::write (const void* const src, const size_t numBytes)
{
memcpy (buffer + bytesInBuffer, src, numBytes);
bytesInBuffer += numBytes;
currentPosition += numBytes;
currentPosition += (int64) numBytes;
}
else
{
@@ -101,7 +101,7 @@ bool FileOutputStream::write (const void* const src, const size_t numBytes)
{
memcpy (buffer + bytesInBuffer, src, numBytes);
bytesInBuffer += numBytes;
currentPosition += numBytes;
currentPosition += (int64) numBytes;
}
else
{
@@ -110,7 +110,7 @@ bool FileOutputStream::write (const void* const src, const size_t numBytes)
if (bytesWritten < 0)
return false;
currentPosition += bytesWritten;
currentPosition += (int64) bytesWritten;
return bytesWritten == (ssize_t) numBytes;
}
}
@@ -126,7 +126,7 @@ bool FileOutputStream::writeRepeatedByte (uint8 byte, size_t numBytes)
{
memset (buffer + bytesInBuffer, byte, numBytes);
bytesInBuffer += numBytes;
currentPosition += numBytes;
currentPosition += (int64) numBytes;
return true;
}


+ 1
- 1
source/modules/juce_core/javascript/juce_JSON.cpp View File

@@ -579,7 +579,7 @@ public:
case 1: return r.nextInt();
case 2: return r.nextInt64();
case 3: return r.nextBool();
case 4: return r.nextDouble();
case 4: return String (r.nextDouble(), 8).getDoubleValue();
case 5: return createRandomWideCharString (r);
case 6:


+ 9
- 0
source/modules/juce_core/javascript/juce_Javascript.cpp View File

@@ -149,6 +149,10 @@ struct JavascriptEngine::RootObject : public DynamicObject
if (const var* prop = getPropertyPointer (p, functionName))
return *prop;
}
// if there's a class with an overridden DynamicObject::hasMethod, this avoids an error
if (o->hasMethod (functionName))
return var();
}
if (targetObject.isString())
@@ -699,6 +703,11 @@ struct JavascriptEngine::RootObject : public DynamicObject
if (FunctionObject* fo = dynamic_cast<FunctionObject*> (function.getObject()))
return fo->invoke (s, args);
if (DotOperator* dot = dynamic_cast<DotOperator*> (object.get()))
if (DynamicObject* o = thisObject.getDynamicObject())
if (o->hasMethod (dot->child)) // allow an overridden DynamicObject::invokeMethod to accept a method call.
return o->invokeMethod (dot->child, args);
location.throwError ("This expression is not a function!"); return var();
}


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

@@ -107,6 +107,11 @@
#include <android/log.h>
#endif
//==============================================================================
#ifndef JUCE_STANDALONE_APPLICATION
JUCE_COMPILER_WARNING ("Please re-save your Introjucer project with the latest Introjucer version to avoid this warning")
#define JUCE_STANDALONE_APPLICATION 0
#endif
//==============================================================================
namespace juce


+ 49
- 10
source/modules/juce_core/maths/juce_MathsFunctions.h View File

@@ -274,6 +274,19 @@ inline void swapVariables (Type& variable1, Type& variable2)
std::swap (variable1, variable2);
}
/** Handy function for avoiding unused variables warning. */
template <typename Type1>
void ignoreUnused (const Type1&) noexcept {}
template <typename Type1, typename Type2>
void ignoreUnused (const Type1&, const Type2&) noexcept {}
template <typename Type1, typename Type2, typename Type3>
void ignoreUnused (const Type1&, const Type2&, const Type3&) noexcept {}
template <typename Type1, typename Type2, typename Type3, typename Type4>
void ignoreUnused (const Type1&, const Type2&, const Type3&, const Type4&) noexcept {}
/** Handy function for getting the number of elements in a simple const C array.
E.g.
@code
@@ -299,11 +312,23 @@ template <typename Type>
inline Type juce_hypot (Type a, Type b) noexcept
{
#if JUCE_MSVC
return static_cast <Type> (_hypot (a, b));
return static_cast<Type> (_hypot (a, b));
#else
return static_cast<Type> (hypot (a, b));
#endif
}
#ifndef DOXYGEN
template <>
inline float juce_hypot (float a, float b) noexcept
{
#if JUCE_MSVC
return (_hypotf (a, b));
#else
return static_cast <Type> (hypot (a, b));
return (hypotf (a, b));
#endif
}
#endif
/** 64-bit abs function. */
inline int64 abs64 (const int64 n) noexcept
@@ -333,13 +358,27 @@ const float float_Pi = 3.14159265358979323846f;
/** The isfinite() method seems to vary between platforms, so this is a
platform-independent function for it.
*/
template <typename FloatingPointType>
inline bool juce_isfinite (FloatingPointType value)
template <typename NumericType>
inline bool juce_isfinite (NumericType) noexcept
{
#if JUCE_WINDOWS
return _finite (value);
#elif JUCE_ANDROID
return isfinite (value);
return true; // Integer types are always finite
}
template <>
inline bool juce_isfinite (float value) noexcept
{
#if JUCE_MSVC
return _finite (value) != 0;
#else
return std::isfinite (value);
#endif
}
template <>
inline bool juce_isfinite (double value) noexcept
{
#if JUCE_MSVC
return _finite (value) != 0;
#else
return std::isfinite (value);
#endif
@@ -495,12 +534,12 @@ NumericType square (NumericType n) noexcept
}
//==============================================================================
#if (JUCE_INTEL && JUCE_32BIT) || defined (DOXYGEN)
#if JUCE_INTEL || defined (DOXYGEN)
/** This macro can be applied to a float variable to check whether it contains a denormalised
value, and to normalise it if necessary.
On CPUs that aren't vulnerable to denormalisation problems, this will have no effect.
*/
#define JUCE_UNDENORMALISE(x) x += 1.0f; x -= 1.0f;
#define JUCE_UNDENORMALISE(x) { (x) += 0.1f; (x) -= 0.1f; }
#else
#define JUCE_UNDENORMALISE(x)
#endif


+ 1
- 1
source/modules/juce_core/memory/juce_ByteOrder.h View File

@@ -153,7 +153,7 @@ inline uint64 ByteOrder::swap (uint64 value) noexcept
#elif JUCE_USE_MSVC_INTRINSICS
return _byteswap_uint64 (value);
#else
return (((int64) swap ((uint32) value)) << 32) | swap ((uint32) (value >> 32));
return (((uint64) swap ((uint32) value)) << 32) | swap ((uint32) (value >> 32));
#endif
}


+ 13
- 13
source/modules/juce_core/memory/juce_HeapBlock.h View File

@@ -36,7 +36,7 @@ namespace HeapBlockHelper
struct ThrowOnFail { static void check (void*) {} };
template<>
struct ThrowOnFail <true> { static void check (void* data) { if (data == nullptr) throw std::bad_alloc(); } };
struct ThrowOnFail<true> { static void check (void* data) { if (data == nullptr) throw std::bad_alloc(); } };
}
#endif
@@ -67,7 +67,7 @@ namespace HeapBlockHelper
..you could just write this:
@code
HeapBlock <int> temp (1024);
HeapBlock<int> temp (1024);
memcpy (temp, xyz, 1024 * sizeof (int));
temp.calloc (2048);
temp[0] = 1234;
@@ -109,7 +109,7 @@ public:
other constructor that takes an InitialisationState parameter.
*/
explicit HeapBlock (const size_t numElements)
: data (static_cast <ElementType*> (std::malloc (numElements * sizeof (ElementType))))
: data (static_cast<ElementType*> (std::malloc (numElements * sizeof (ElementType))))
{
throwOnAllocationFailure();
}
@@ -120,7 +120,7 @@ public:
or left uninitialised.
*/
HeapBlock (const size_t numElements, const bool initialiseToZero)
: data (static_cast <ElementType*> (initialiseToZero
: data (static_cast<ElementType*> (initialiseToZero
? std::calloc (numElements, sizeof (ElementType))
: std::malloc (numElements * sizeof (ElementType))))
{
@@ -166,13 +166,13 @@ public:
This may be a null pointer if the data hasn't yet been allocated, or if it has been
freed by calling the free() method.
*/
inline operator void*() const noexcept { return static_cast <void*> (data); }
inline operator void*() const noexcept { return static_cast<void*> (data); }
/** Returns a void pointer to the allocated data.
This may be a null pointer if the data hasn't yet been allocated, or if it has been
freed by calling the free() method.
*/
inline operator const void*() const noexcept { return static_cast <const void*> (data); }
inline operator const void*() const noexcept { return static_cast<const void*> (data); }
/** Lets you use indirect calls to the first element in the array.
Obviously this will cause problems if the array hasn't been initialised, because it'll
@@ -220,7 +220,7 @@ public:
void malloc (const size_t newNumElements, const size_t elementSize = sizeof (ElementType))
{
std::free (data);
data = static_cast <ElementType*> (std::malloc (newNumElements * elementSize));
data = static_cast<ElementType*> (std::malloc (newNumElements * elementSize));
throwOnAllocationFailure();
}
@@ -230,7 +230,7 @@ public:
void calloc (const size_t newNumElements, const size_t elementSize = sizeof (ElementType))
{
std::free (data);
data = static_cast <ElementType*> (std::calloc (newNumElements, elementSize));
data = static_cast<ElementType*> (std::calloc (newNumElements, elementSize));
throwOnAllocationFailure();
}
@@ -241,7 +241,7 @@ public:
void allocate (const size_t newNumElements, bool initialiseToZero)
{
std::free (data);
data = static_cast <ElementType*> (initialiseToZero
data = static_cast<ElementType*> (initialiseToZero
? std::calloc (newNumElements, sizeof (ElementType))
: std::malloc (newNumElements * sizeof (ElementType)));
throwOnAllocationFailure();
@@ -254,15 +254,15 @@ public:
*/
void realloc (const size_t newNumElements, const size_t elementSize = sizeof (ElementType))
{
data = static_cast <ElementType*> (data == nullptr ? std::malloc (newNumElements * elementSize)
: std::realloc (data, newNumElements * elementSize));
data = static_cast<ElementType*> (data == nullptr ? std::malloc (newNumElements * elementSize)
: std::realloc (data, newNumElements * elementSize));
throwOnAllocationFailure();
}
/** Frees any currently-allocated data.
This will free the data and reset this object to be a null pointer.
*/
void free()
void free() noexcept
{
std::free (data);
data = nullptr;
@@ -272,7 +272,7 @@ public:
The two objects simply exchange their data pointers.
*/
template <bool otherBlockThrows>
void swapWith (HeapBlock <ElementType, otherBlockThrows>& other) noexcept
void swapWith (HeapBlock<ElementType, otherBlockThrows>& other) noexcept
{
std::swap (data, other.data);
}


+ 1
- 1
source/modules/juce_core/memory/juce_MemoryBlock.cpp View File

@@ -259,7 +259,7 @@ void MemoryBlock::copyTo (void* const dst, int offset, size_t num) const noexcep
if ((size_t) offset + num > size)
{
const size_t newNum = size - (size_t) offset;
const size_t newNum = (size_t) size - (size_t) offset;
zeromem (d + newNum, num - newNum);
num = newNum;
}


+ 1
- 1
source/modules/juce_core/memory/juce_Singleton.h View File

@@ -44,7 +44,7 @@
destructor, in case it is deleted by other means than deleteInstance()
Clients can then call the static method MyClass::getInstance() to get a pointer
to the singleton, or MyClass::getInstanceWithoutCreating() which will return 0 if
to the singleton, or MyClass::getInstanceWithoutCreating() which will return nullptr if
no instance currently exists.
e.g. @code


+ 30
- 2
source/modules/juce_core/native/java/JuceAppActivity.java View File

@@ -331,15 +331,26 @@ public class JuceAppActivity extends Activity
setFocusableInTouchMode (true);
setOnFocusChangeListener (this);
requestFocus();
// swap red and blue colours to match internal opengl texture format
ColorMatrix colorMatrix = new ColorMatrix();
float[] colorTransform = { 0, 0, 1.0f, 0, 0,
0, 1.0f, 0, 0, 0,
1.0f, 0, 0, 0, 0,
0, 0, 0, 1.0f, 0 };
colorMatrix.set (colorTransform);
paint.setColorFilter (new ColorMatrixColorFilter (colorMatrix));
}
//==============================================================================
private native void handlePaint (long host, Canvas canvas);
private native void handlePaint (long host, Canvas canvas, Paint paint);
@Override
public void onDraw (Canvas canvas)
{
handlePaint (host, canvas);
handlePaint (host, canvas, paint);
}
@Override
@@ -350,6 +361,7 @@ public class JuceAppActivity extends Activity
private boolean opaque;
private long host;
private Paint paint = new Paint();
//==============================================================================
private native void handleMouseDown (long host, int index, float x, float y, long time);
@@ -448,6 +460,22 @@ public class JuceAppActivity extends Activity
return true;
}
@Override
public boolean onKeyMultiple (int keyCode, int count, KeyEvent event)
{
if (keyCode != KeyEvent.KEYCODE_UNKNOWN || event.getAction() != KeyEvent.ACTION_MULTIPLE)
return super.onKeyMultiple (keyCode, count, event);
if (event.getCharacters() != null)
{
int utf8Char = event.getCharacters().codePointAt (0);
handleKeyDown (host, utf8Char, utf8Char);
return true;
}
return false;
}
// this is here to make keyboard entry work on a Galaxy Tab2 10.1
@Override
public InputConnection onCreateInputConnection (EditorInfo outAttrs)


+ 2
- 2
source/modules/juce_core/native/juce_linux_CommonFile.cpp View File

@@ -138,8 +138,8 @@ private:
JUCE_DECLARE_NON_COPYABLE (Pimpl)
};
DirectoryIterator::NativeIterator::NativeIterator (const File& directory, const String& wildCard)
: pimpl (new DirectoryIterator::NativeIterator::Pimpl (directory, wildCard))
DirectoryIterator::NativeIterator::NativeIterator (const File& directory, const String& wildCardStr)
: pimpl (new DirectoryIterator::NativeIterator::Pimpl (directory, wildCardStr))
{
}


+ 8
- 4
source/modules/juce_core/native/juce_linux_Files.cpp View File

@@ -150,7 +150,10 @@ File File::getSpecialLocation (const SpecialLocationType type)
case currentExecutableFile:
case currentApplicationFile:
#if ! JUCE_STANDALONE_APPLICATION
return juce_getExecutableFile();
#endif
// deliberate fall-through if this is not a shared-library
case hostApplicationPath:
{
@@ -216,7 +219,7 @@ bool Process::openDocument (const String& fileName, const String& parameters)
cmdString = cmdLines.joinIntoString (" || ");
}
const char* const argv[4] = { "/bin/sh", "-c", cmdString.toUTF8(), 0 };
const char* const argv[4] = { "/bin/sh", "-c", cmdString.toUTF8(), nullptr };
#if JUCE_USE_VFORK
const int cpid = vfork();
@@ -226,11 +229,12 @@ bool Process::openDocument (const String& fileName, const String& parameters)
if (cpid == 0)
{
#if ! JUCE_USE_VFORK
setsid();
#endif
// Child process
execve (argv[0], (char**) argv, environ);
exit (0);
if (execvp (argv[0], (char**) argv) < 0)
_exit (0);
}
return cpid >= 0;


+ 8
- 8
source/modules/juce_core/native/juce_linux_Network.cpp View File

@@ -127,7 +127,7 @@ public:
if (select (socketHandle + 1, &readbits, 0, 0, &tv) <= 0)
return 0; // (timeout)
const int bytesRead = jmax (0, (int) recv (socketHandle, buffer, bytesToRead, MSG_WAITALL));
const int bytesRead = jmax (0, (int) recv (socketHandle, buffer, (size_t) bytesToRead, MSG_WAITALL));
if (bytesRead == 0)
finished = true;
@@ -182,7 +182,7 @@ private:
}
int createConnection (URL::OpenStreamProgressCallback* progressCallback, void* progressCallbackContext,
const int numRedirectsToFollow)
const int numRedirects)
{
closeSocket (false);
@@ -193,7 +193,7 @@ private:
else if (timeOutMs < 0)
timeOutTime = 0xffffffff;
else
timeOutTime += timeOutMs;
timeOutTime += (uint32) timeOutMs;
String hostName, hostPath;
int hostPort;
@@ -279,7 +279,7 @@ private:
String location (findHeaderItem (headerLines, "Location:"));
if (++levelsOfRedirection <= numRedirectsToFollow
if (++levelsOfRedirection <= numRedirects
&& status >= 300 && status < 400
&& location.isNotEmpty() && location != address)
{
@@ -295,7 +295,7 @@ private:
}
address = location;
return createConnection (progressCallback, progressCallbackContext, numRedirectsToFollow);
return createConnection (progressCallback, progressCallbackContext, numRedirects);
}
return status;
@@ -391,12 +391,12 @@ private:
const int numToSend = jmin (1024, (int) (requestHeader.getSize() - totalHeaderSent));
if (send (socketHandle, static_cast <const char*> (requestHeader.getData()) + totalHeaderSent, numToSend, 0) != numToSend)
if (send (socketHandle, static_cast <const char*> (requestHeader.getData()) + totalHeaderSent, (size_t) numToSend, 0) != numToSend)
return false;
totalHeaderSent += numToSend;
totalHeaderSent += (size_t) numToSend;
if (progressCallback != nullptr && ! progressCallback (progressCallbackContext, totalHeaderSent, requestHeader.getSize()))
if (progressCallback != nullptr && ! progressCallback (progressCallbackContext, (int) totalHeaderSent, (int) requestHeader.getSize()))
return false;
}


+ 22
- 5
source/modules/juce_core/native/juce_linux_SystemStats.cpp View File

@@ -55,10 +55,10 @@ bool SystemStats::isOperatingSystem64Bit()
//==============================================================================
namespace LinuxStatsHelpers
{
String getCpuInfo (const char* const key)
String getConfigFileValue (const char* file, const char* const key)
{
StringArray lines;
File ("/proc/cpuinfo").readLines (lines);
File (file).readLines (lines);
for (int i = lines.size(); --i >= 0;) // (NB - it's important that this runs in reverse order)
if (lines[i].upToFirstOccurrenceOf (":", false, false).trim().equalsIgnoreCase (key))
@@ -66,6 +66,11 @@ namespace LinuxStatsHelpers
return String();
}
String getCpuInfo (const char* key)
{
return getConfigFileValue ("/proc/cpuinfo", key);
}
}
String SystemStats::getDeviceDescription()
@@ -93,14 +98,14 @@ int SystemStats::getMemorySizeInMegabytes()
struct sysinfo sysi;
if (sysinfo (&sysi) == 0)
return sysi.totalram * sysi.mem_unit / (1024 * 1024);
return (int) (sysi.totalram * sysi.mem_unit / (1024 * 1024));
return 0;
}
int SystemStats::getPageSize()
{
return sysconf (_SC_PAGESIZE);
return (int) sysconf (_SC_PAGESIZE);
}
//==============================================================================
@@ -150,6 +155,8 @@ void CPUInformation::initialise() noexcept
hasSSE2 = flags.contains ("sse2");
hasSSE3 = flags.contains ("sse3");
has3DNow = flags.contains ("3dnow");
hasSSSE3 = flags.contains ("ssse3");
hasAVX = flags.contains ("avx");
numCpus = LinuxStatsHelpers::getCpuInfo ("processor").getIntValue() + 1;
}
@@ -160,7 +167,7 @@ uint32 juce_millisecondsSinceStartup() noexcept
timespec t;
clock_gettime (CLOCK_MONOTONIC, &t);
return t.tv_sec * 1000 + t.tv_nsec / 1000000;
return (uint32) (t.tv_sec * 1000 + t.tv_nsec / 1000000);
}
int64 Time::getHighResolutionTicks() noexcept
@@ -189,3 +196,13 @@ bool Time::setSystemTimeToThisTime() const
return settimeofday (&t, 0) == 0;
}
JUCE_API bool JUCE_CALLTYPE juce_isRunningUnderDebugger()
{
#if JUCE_BSD
return false;
#else
return LinuxStatsHelpers::getConfigFileValue ("/proc/self/status", "TracerPid")
.getIntValue() > 0;
#endif
}

+ 0
- 22
source/modules/juce_core/native/juce_linux_Threads.cpp View File

@@ -52,28 +52,6 @@ JUCE_API void JUCE_CALLTYPE Process::setPriority (const ProcessPriority prior)
pthread_setschedparam (pthread_self(), policy, &param);
}
JUCE_API bool JUCE_CALLTYPE juce_isRunningUnderDebugger()
{
#if JUCE_BSD
return false;
#else
static char testResult = 0;
if (testResult == 0)
{
testResult = (char) ptrace (PT_TRACE_ME, 0, 0, 0);
if (testResult >= 0)
{
ptrace (PT_DETACH, 0, (caddr_t) 1, 0);
testResult = 1;
}
}
return testResult < 0;
#endif
}
JUCE_API bool JUCE_CALLTYPE Process::isRunningUnderDebugger()
{
return juce_isRunningUnderDebugger();


+ 4
- 9
source/modules/juce_core/native/juce_mac_Files.mm View File

@@ -110,7 +110,7 @@ namespace FileHelpers
static bool launchExecutable (const String& pathAndArguments)
{
const char* const argv[4] = { "/bin/sh", "-c", pathAndArguments.toUTF8(), 0 };
const char* const argv[4] = { "/bin/sh", "-c", pathAndArguments.toUTF8(), nullptr };
#if JUCE_USE_VFORK
const int cpid = vfork();
@@ -121,16 +121,11 @@ namespace FileHelpers
if (cpid == 0)
{
// Child process
if (execve (argv[0], (char**) argv, 0) < 0)
exit (0);
}
else
{
if (cpid < 0)
return false;
if (execvp (argv[0], (char**) argv) < 0)
_exit (0);
}
return true;
return cpid >= 0;
}
}


+ 8
- 4
source/modules/juce_core/native/juce_mac_Network.mm View File

@@ -128,7 +128,8 @@ public:
hasFailed (false),
hasFinished (false),
numRedirectsToFollow (maxRedirects),
numRedirects (0)
numRedirects (0),
latestTotalBytes (0)
{
static DelegateClass cls;
delegate = [cls.createInstance() init];
@@ -152,7 +153,7 @@ public:
while (isThreadRunning() && ! initialised)
{
if (callback != nullptr)
callback (context, -1, (int) [[request HTTPBody] length]);
callback (context, latestTotalBytes, (int) [[request HTTPBody] length]);
Thread::sleep (1);
}
@@ -203,7 +204,6 @@ public:
[data setLength: 0];
}
initialised = true;
contentLength = [response expectedContentLength];
[headers release];
@@ -215,6 +215,8 @@ public:
headers = [[httpResponse allHeaderFields] retain];
statusCode = (int) [httpResponse statusCode];
}
initialised = true;
}
NSURLRequest* willSendRequest (NSURLRequest* newRequest, NSURLResponse* redirectResponse)
@@ -245,8 +247,9 @@ public:
initialised = true;
}
void didSendBodyData (NSInteger /*totalBytesWritten*/, NSInteger /*totalBytesExpected*/)
void didSendBodyData (NSInteger totalBytesWritten, NSInteger /*totalBytesExpected*/)
{
latestTotalBytes = static_cast<int> (totalBytesWritten);
}
void finishedLoading()
@@ -280,6 +283,7 @@ public:
bool initialised, hasFailed, hasFinished;
const int numRedirectsToFollow;
int numRedirects;
int latestTotalBytes;
private:
//==============================================================================


+ 2
- 0
source/modules/juce_core/native/juce_mac_SystemStats.mm View File

@@ -80,6 +80,8 @@ void CPUInformation::initialise() noexcept
hasSSE2 = (d & (1u << 26)) != 0;
has3DNow = (b & (1u << 31)) != 0;
hasSSE3 = (c & (1u << 0)) != 0;
hasSSSE3 = (c & (1u << 9)) != 0;
hasAVX = (c & (1u << 28)) != 0;
#endif
#if JUCE_IOS || (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5)


+ 5
- 1
source/modules/juce_core/native/juce_osx_ObjCHelpers.h View File

@@ -65,14 +65,16 @@ namespace
static_cast <CGFloat> (r.getWidth()),
static_cast <CGFloat> (r.getHeight()));
}
#endif
// These hacks are a workaround for newer Xcode builds which by default prevent calls to these objc functions..
typedef id (*MsgSendSuperFn) (struct objc_super*, SEL, ...);
static inline MsgSendSuperFn getMsgSendSuperFn() noexcept { return (MsgSendSuperFn) (void*) objc_msgSendSuper; }
#if ! JUCE_PPC
typedef double (*MsgSendFPRetFn) (id, SEL op, ...);
static inline MsgSendFPRetFn getMsgSendFPRetFn() noexcept { return (MsgSendFPRetFn) (void*) objc_msgSend_fpret; }
#endif
#endif
}
//==============================================================================
@@ -147,11 +149,13 @@ struct ObjCClass
jassert (b); (void) b;
}
#if JUCE_MAC
static id sendSuperclassMessage (id self, SEL selector)
{
objc_super s = { self, [SuperclassType class] };
return getMsgSendSuperFn() (&s, selector);
}
#endif
template <typename Type>
static Type getIvar (id self, const char* name)


+ 42
- 16
source/modules/juce_core/native/juce_posix_SharedCode.h View File

@@ -596,12 +596,38 @@ File juce_getExecutableFile()
{
Dl_info exeInfo;
dladdr ((void*) juce_getExecutableFile, &exeInfo);
return CharPointer_UTF8 (exeInfo.dli_fname);
const CharPointer_UTF8 filename (exeInfo.dli_fname);
// if the filename is absolute simply return it
if (File::isAbsolutePath (filename))
return filename;
// if the filename is relative construct from CWD
if (filename[0] == '.')
return File::getCurrentWorkingDirectory().getChildFile (filename).getFullPathName();
// filename is abstract, look up in PATH
if (const char* const envpath = ::getenv ("PATH"))
{
StringArray paths (StringArray::fromTokens (envpath, ":", ""));
for (int i=paths.size(); --i>=0;)
{
const File filepath (File (paths[i]).getChildFile (filename));
if (filepath.existsAsFile())
return filepath.getFullPathName();
}
}
// if we reach this, we failed to find ourselves...
jassertfalse;
return filename;
}
};
static String filename (DLAddrReader::getFilename());
return File::getCurrentWorkingDirectory().getChildFile (filename);
return filename;
#endif
}
@@ -961,22 +987,22 @@ void JUCE_CALLTYPE Thread::setCurrentThreadAffinityMask (const uint32 affinityMa
if ((affinityMask & (1 << i)) != 0)
CPU_SET (i, &affinity);
/*
N.B. If this line causes a compile error, then you've probably not got the latest
version of glibc installed.
If you don't want to update your copy of glibc and don't care about cpu affinities,
then you can just disable all this stuff by setting the SUPPORT_AFFINITIES macro to 0.
*/
#if (! JUCE_LINUX) || ((__GLIBC__ * 1000 + __GLIBC_MINOR__) >= 2004)
pthread_setaffinity_np (pthread_self(), sizeof (cpu_set_t), &affinity);
#else
// NB: this call isn't really correct because it sets the affinity of the process,
// not the thread. But it's included here as a fallback for people who are using
// ridiculously old versions of glibc
sched_setaffinity (getpid(), sizeof (cpu_set_t), &affinity);
#endif
sched_yield();
#else
/* affinities aren't supported because either the appropriate header files weren't found,
or the SUPPORT_AFFINITIES macro was turned off
*/
// affinities aren't supported because either the appropriate header files weren't found,
// or the SUPPORT_AFFINITIES macro was turned off
jassertfalse;
(void) affinityMask;
ignoreUnused (affinityMask);
#endif
}
@@ -1057,8 +1083,8 @@ public:
close (pipeHandles[1]);
#endif
execvp (argv[0], argv.getRawDataPointer());
exit (-1);
if (execvp (argv[0], argv.getRawDataPointer()) < 0)
_exit (-1);
}
else
{
@@ -1285,7 +1311,7 @@ private:
{
struct timespec t;
clock_gettime (CLOCK_MONOTONIC, &t);
time = 1000000000 * (int64) t.tv_sec + t.tv_nsec;
time = (uint64) (1000000000 * (int64) t.tv_sec + (int64) t.tv_nsec);
}
void wait() noexcept


+ 10
- 2
source/modules/juce_core/native/juce_win32_SystemStats.cpp View File

@@ -105,6 +105,8 @@ void CPUInformation::initialise() noexcept
hasSSE = (info[3] & (1 << 25)) != 0;
hasSSE2 = (info[3] & (1 << 26)) != 0;
hasSSE3 = (info[2] & (1 << 0)) != 0;
hasAVX = (info[2] & (1 << 28)) != 0;
hasSSSE3 = (info[2] & (1 << 9)) != 0;
has3DNow = (info[1] & (1 << 31)) != 0;
SYSTEM_INFO systemInfo;
@@ -131,7 +133,12 @@ static bool isWindowsVersionOrLater (SystemStats::OperatingSystemType target)
zerostruct (info);
info.dwOSVersionInfoSize = sizeof (OSVERSIONINFOEX);
if (target >= SystemStats::WinVista)
if (target >= SystemStats::Windows10)
{
info.dwMajorVersion = 10;
info.dwMinorVersion = 0;
}
else if (target >= SystemStats::WinVista)
{
info.dwMajorVersion = 6;
@@ -166,7 +173,7 @@ static bool isWindowsVersionOrLater (SystemStats::OperatingSystemType target)
SystemStats::OperatingSystemType SystemStats::getOperatingSystemType()
{
const SystemStats::OperatingSystemType types[]
= { Windows8_1, Windows8_0, Windows7, WinVista, WinXP, Win2000 };
= { Windows10, Windows8_1, Windows8_0, Windows7, WinVista, WinXP, Win2000 };
for (int i = 0; i < numElementsInArray (types); ++i)
if (isWindowsVersionOrLater (types[i]))
@@ -182,6 +189,7 @@ String SystemStats::getOperatingSystemName()
switch (getOperatingSystemType())
{
case Windows10: name = "Windows 10"; break;
case Windows8_1: name = "Windows 8.1"; break;
case Windows8_0: name = "Windows 8.0"; break;
case Windows7: name = "Windows 7"; break;


+ 1
- 1
source/modules/juce_core/network/juce_IPAddress.cpp View File

@@ -126,7 +126,7 @@ static void findIPAddresses (int sock, Array<IPAddress>& result)
cfg.ifc_buf += IFNAMSIZ + cfg.ifc_req->ifr_addr.sa_len;
}
#else
for (size_t i = 0; i < cfg.ifc_len / sizeof (struct ifreq); ++i)
for (size_t i = 0; i < (size_t) cfg.ifc_len / (size_t) sizeof (struct ifreq); ++i)
{
const ifreq& item = cfg.ifc_req[i];


+ 240
- 174
source/modules/juce_core/network/juce_Socket.cpp View File

@@ -75,9 +75,59 @@ namespace SocketHelpers
: (setsockopt (handle, IPPROTO_TCP, TCP_NODELAY, (const char*) &one, sizeof (one)) == 0));
}
static bool bindSocketToPort (const SocketHandle handle, const int port) noexcept
static void closeSocket (volatile int& handle, CriticalSection& readLock,
const bool isListener, int portNumber, bool& connected) noexcept
{
if (handle <= 0 || port <= 0)
const SocketHandle h = handle;
handle = -1;
#if JUCE_WINDOWS
ignoreUnused (portNumber, isListener, readLock);
if (h != SOCKET_ERROR || connected)
closesocket (h);
// make sure any read process finishes before we delete the socket
CriticalSection::ScopedLockType lock(readLock);
connected = false;
#else
if (connected)
{
connected = false;
if (isListener)
{
// need to do this to interrupt the accept() function..
StreamingSocket temp;
temp.connect (IPAddress::local().toString(), portNumber, 1000);
}
}
if (h != -1)
{
// unblock any pending read requests
::shutdown (h, SHUT_RDWR);
{
// see man-page of recv on linux about a race condition where the
// shutdown command is lost if the receiving thread does not have
// a chance to process before close is called. On Mac OS X shutdown
// does not unblock a select call, so using a lock here will dead-lock
// both threads.
#if JUCE_LINUX
CriticalSection::ScopedLockType lock (readLock);
::close (h);
#else
::close (h);
CriticalSection::ScopedLockType lock (readLock);
#endif
}
}
#endif
}
static bool bindSocket (const SocketHandle handle, const int port, const String& address) noexcept
{
if (handle <= 0 || port < 0)
return false;
struct sockaddr_in servTmpAddr;
@@ -86,30 +136,64 @@ namespace SocketHelpers
servTmpAddr.sin_addr.s_addr = htonl (INADDR_ANY);
servTmpAddr.sin_port = htons ((uint16) port);
if (address.isNotEmpty())
servTmpAddr.sin_addr.s_addr = ::inet_addr (address.toUTF8());
return bind (handle, (struct sockaddr*) &servTmpAddr, sizeof (struct sockaddr_in)) >= 0;
}
static int getBoundPort (const SocketHandle handle) noexcept
{
if (handle <= 0)
return -1;
struct sockaddr_in sin_addr;
socklen_t len = sizeof (sin_addr);
if (getsockname (handle, (struct sockaddr*) &sin_addr, &len) == 0)
return ntohs (sin_addr.sin_port);
return -1;
}
static int readSocket (const SocketHandle handle,
void* const destBuffer, const int maxBytesToRead,
bool volatile& connected,
const bool blockUntilSpecifiedAmountHasArrived) noexcept
const bool blockUntilSpecifiedAmountHasArrived,
CriticalSection& readLock,
String* senderIP = nullptr,
int* senderPort = nullptr) noexcept
{
int bytesRead = 0;
while (bytesRead < maxBytesToRead)
{
int bytesThisTime;
long bytesThisTime = -1;
char* const buffer = static_cast<char*> (destBuffer) + bytesRead;
const juce_socklen_t numToRead = (juce_socklen_t) (maxBytesToRead - bytesRead);
#if JUCE_WINDOWS
bytesThisTime = recv (handle, static_cast<char*> (destBuffer) + bytesRead, maxBytesToRead - bytesRead, 0);
#else
while ((bytesThisTime = (int) ::read (handle, addBytesToPointer (destBuffer, bytesRead),
(size_t) (maxBytesToRead - bytesRead))) < 0
&& errno == EINTR
&& connected)
{
// avoid race-condition
CriticalSection::ScopedTryLockType lock (readLock);
if (lock.isLocked())
{
if (senderIP == nullptr || senderPort == nullptr)
{
bytesThisTime = ::recv (handle, buffer, numToRead, 0);
}
else
{
sockaddr_in client;
socklen_t clientLen = sizeof (sockaddr);
bytesThisTime = ::recvfrom (handle, buffer, numToRead, 0, (sockaddr*) &client, &clientLen);
*senderIP = String::fromUTF8 (inet_ntoa (client.sin_addr), 16);
*senderPort = ntohs (client.sin_port);
}
}
}
#endif
if (bytesThisTime <= 0 || ! connected)
{
@@ -125,11 +209,20 @@ namespace SocketHelpers
break;
}
return bytesRead;
return (int) bytesRead;
}
static int waitForReadiness (const SocketHandle handle, const bool forReading, const int timeoutMsecs) noexcept
static int waitForReadiness (const volatile int& handle, CriticalSection& readLock,
const bool forReading, const int timeoutMsecs) noexcept
{
// avoid race-condition
CriticalSection::ScopedTryLockType lock (readLock);
if (! lock.isLocked())
return -1;
int h = handle;
struct timeval timeout;
struct timeval* timeoutp;
@@ -146,20 +239,20 @@ namespace SocketHelpers
fd_set rset, wset;
FD_ZERO (&rset);
FD_SET (handle, &rset);
FD_SET (h, &rset);
FD_ZERO (&wset);
FD_SET (handle, &wset);
FD_SET (h, &wset);
fd_set* const prset = forReading ? &rset : nullptr;
fd_set* const pwset = forReading ? nullptr : &wset;
#if JUCE_WINDOWS
if (select ((int) handle + 1, prset, pwset, 0, timeoutp) < 0)
if (select ((int) h + 1, prset, pwset, 0, timeoutp) < 0)
return -1;
#else
{
int result;
while ((result = select (handle + 1, prset, pwset, 0, timeoutp)) < 0
while ((result = select (h + 1, prset, pwset, 0, timeoutp)) < 0
&& errno == EINTR)
{
}
@@ -169,16 +262,20 @@ namespace SocketHelpers
}
#endif
// we are closing
if (handle < 0)
return -1;
{
int opt;
juce_socklen_t len = sizeof (opt);
if (getsockopt (handle, SOL_SOCKET, SO_ERROR, (char*) &opt, &len) < 0
if (getsockopt (h, SOL_SOCKET, SO_ERROR, (char*) &opt, &len) < 0
|| opt != 0)
return -1;
}
return FD_ISSET (handle, forReading ? &rset : &wset) ? 1 : 0;
return FD_ISSET (h, forReading ? &rset : &wset) ? 1 : 0;
}
static bool setSocketBlockingState (const SocketHandle handle, const bool shouldBlock) noexcept
@@ -201,12 +298,7 @@ namespace SocketHelpers
#endif
}
static bool connectSocket (int volatile& handle,
const bool isDatagram,
struct addrinfo** const serverAddress,
const String& hostName,
const int portNumber,
const int timeOutMillisecs) noexcept
static addrinfo* getAddressInfo (const bool isDatagram, const String& hostName, int portNumber)
{
struct addrinfo hints;
zerostruct (hints);
@@ -216,8 +308,22 @@ namespace SocketHelpers
hints.ai_flags = AI_NUMERICSERV;
struct addrinfo* info = nullptr;
if (getaddrinfo (hostName.toUTF8(), String (portNumber).toUTF8(), &hints, &info) != 0
|| info == nullptr)
if (getaddrinfo (hostName.toUTF8(), String (portNumber).toUTF8(), &hints, &info) == 0
&& info != nullptr)
return info;
return nullptr;
}
static bool connectSocket (int volatile& handle,
CriticalSection& readLock,
const String& hostName,
const int portNumber,
const int timeOutMillisecs) noexcept
{
struct addrinfo* info = getAddressInfo (false, hostName, portNumber);
if (info == nullptr)
return false;
if (handle < 0)
@@ -229,19 +335,12 @@ namespace SocketHelpers
return false;
}
if (isDatagram)
{
if (*serverAddress != nullptr)
freeaddrinfo (*serverAddress);
*serverAddress = info;
return true;
}
setSocketBlockingState (handle, false);
const int result = ::connect (handle, info->ai_addr, (socklen_t) info->ai_addrlen);
freeaddrinfo (info);
bool retval = (result >= 0);
if (result < 0)
{
#if JUCE_WINDOWS
@@ -250,18 +349,17 @@ namespace SocketHelpers
if (errno == EINPROGRESS)
#endif
{
if (waitForReadiness (handle, false, timeOutMillisecs) != 1)
{
setSocketBlockingState (handle, true);
return false;
}
if (waitForReadiness (handle, readLock, false, timeOutMillisecs) == 1)
retval = true;
}
}
setSocketBlockingState (handle, true);
resetSocketOptions (handle, false, false);
return true;
if (retval)
resetSocketOptions (handle, false, false);
return retval;
}
static void makeReusable (int handle) noexcept
@@ -269,6 +367,23 @@ namespace SocketHelpers
const int reuse = 1;
setsockopt (handle, SOL_SOCKET, SO_REUSEADDR, (const char*) &reuse, sizeof (reuse));
}
static bool multicast (int handle, const String& multicastIPAddress,
const String& interfaceIPAddress, bool join) noexcept
{
struct ip_mreq mreq;
zerostruct (mreq);
mreq.imr_multiaddr.s_addr = inet_addr (multicastIPAddress.toUTF8());
mreq.imr_interface.s_addr = INADDR_ANY;
if (interfaceIPAddress.isNotEmpty())
mreq.imr_interface.s_addr = inet_addr (interfaceIPAddress.toUTF8());
int joinCmd = join ? IP_ADD_MEMBERSHIP : IP_DROP_MEMBERSHIP;
return setsockopt (handle, IPPROTO_IP, joinCmd, (const char*) &mreq, sizeof (mreq)) == 0;
}
}
//==============================================================================
@@ -298,11 +413,10 @@ StreamingSocket::~StreamingSocket()
}
//==============================================================================
int StreamingSocket::read (void* destBuffer, const int maxBytesToRead,
const bool blockUntilSpecifiedAmountHasArrived)
int StreamingSocket::read (void* destBuffer, const int maxBytesToRead, bool shouldBlock)
{
return (connected && ! isListener) ? SocketHelpers::readSocket (handle, destBuffer, maxBytesToRead,
connected, blockUntilSpecifiedAmountHasArrived)
connected, shouldBlock, readLock)
: -1;
}
@@ -311,32 +425,31 @@ int StreamingSocket::write (const void* sourceBuffer, const int numBytesToWrite)
if (isListener || ! connected)
return -1;
#if JUCE_WINDOWS
return send (handle, (const char*) sourceBuffer, numBytesToWrite, 0);
#else
int result;
while ((result = (int) ::write (handle, sourceBuffer, (size_t) numBytesToWrite)) < 0
&& errno == EINTR)
{
}
return result;
#endif
return (int) ::send (handle, (const char*) sourceBuffer, (juce_socklen_t) numBytesToWrite, 0);
}
//==============================================================================
int StreamingSocket::waitUntilReady (const bool readyForReading,
const int timeoutMsecs) const
{
return connected ? SocketHelpers::waitForReadiness (handle, readyForReading, timeoutMsecs)
return connected ? SocketHelpers::waitForReadiness (handle, readLock, readyForReading, timeoutMsecs)
: -1;
}
//==============================================================================
bool StreamingSocket::bindToPort (const int port)
{
return SocketHelpers::bindSocketToPort (handle, port);
return bindToPort (port, String());
}
bool StreamingSocket::bindToPort (const int port, const String& addr)
{
return SocketHelpers::bindSocket (handle, port, addr);
}
int StreamingSocket::getBoundPort() const noexcept
{
return SocketHelpers::getBoundPort (handle);
}
bool StreamingSocket::connect (const String& remoteHostName,
@@ -356,7 +469,7 @@ bool StreamingSocket::connect (const String& remoteHostName,
portNumber = remotePortNumber;
isListener = false;
connected = SocketHelpers::connectSocket (handle, false, nullptr, remoteHostName,
connected = SocketHelpers::connectSocket (handle, readLock, remoteHostName,
remotePortNumber, timeOutMillisecs);
if (! (connected && SocketHelpers::resetSocketOptions (handle, false, false)))
@@ -370,30 +483,7 @@ bool StreamingSocket::connect (const String& remoteHostName,
void StreamingSocket::close()
{
#if JUCE_WINDOWS
if (handle != SOCKET_ERROR || connected)
closesocket (handle);
connected = false;
#else
if (connected)
{
connected = false;
if (isListener)
{
// need to do this to interrupt the accept() function..
StreamingSocket temp;
temp.connect (IPAddress::local().toString(), portNumber, 1000);
}
}
if (handle != -1)
{
::shutdown (handle, SHUT_RDWR);
::close (handle);
}
#endif
SocketHelpers::closeSocket (handle, readLock, isListener, portNumber, connected);
hostName.clear();
portNumber = 0;
@@ -470,133 +560,109 @@ bool StreamingSocket::isLocal() const noexcept
//==============================================================================
//==============================================================================
DatagramSocket::DatagramSocket (const int localPortNumber, const bool canBroadcast)
: portNumber (0),
handle (-1),
connected (true),
allowBroadcast (canBroadcast),
serverAddress (nullptr)
DatagramSocket::DatagramSocket (const bool canBroadcast)
: handle (-1),
isBound (false),
lastServerPort (-1),
lastServerAddress (nullptr)
{
SocketHelpers::initSockets();
handle = (int) socket (AF_INET, SOCK_DGRAM, 0);
SocketHelpers::resetSocketOptions (handle, true, canBroadcast);
SocketHelpers::makeReusable (handle);
bindToPort (localPortNumber);
}
DatagramSocket::DatagramSocket (const String& host, const int portNum,
const int h, const int localPortNumber)
: hostName (host),
portNumber (portNum),
handle (h),
connected (true),
allowBroadcast (false),
serverAddress (nullptr)
{
SocketHelpers::initSockets();
SocketHelpers::resetSocketOptions (h, true, allowBroadcast);
bindToPort (localPortNumber);
}
DatagramSocket::~DatagramSocket()
{
close();
if (lastServerAddress != nullptr)
freeaddrinfo (static_cast <struct addrinfo*> (lastServerAddress));
if (serverAddress != nullptr)
freeaddrinfo (static_cast <struct addrinfo*> (serverAddress));
}
void DatagramSocket::close()
{
#if JUCE_WINDOWS
closesocket (handle);
connected = false;
#else
connected = false;
::close (handle);
#endif
hostName.clear();
portNumber = 0;
handle = -1;
bool connected = false;
SocketHelpers::closeSocket (handle, readLock, false, 0, connected);
}
bool DatagramSocket::bindToPort (const int port)
{
return SocketHelpers::bindSocketToPort (handle, port);
return bindToPort (port, String());
}
bool DatagramSocket::connect (const String& remoteHostName,
const int remotePortNumber,
const int timeOutMillisecs)
bool DatagramSocket::bindToPort (const int port, const String& addr)
{
if (connected)
close();
hostName = remoteHostName;
portNumber = remotePortNumber;
connected = SocketHelpers::connectSocket (handle, true, (struct addrinfo**) &serverAddress,
remoteHostName, remotePortNumber,
timeOutMillisecs);
if (! (connected && SocketHelpers::resetSocketOptions (handle, true, allowBroadcast)))
if (SocketHelpers::bindSocket (handle, port, addr))
{
close();
return false;
isBound = true;
lastBindAddress = addr;
return true;
}
return true;
return false;
}
DatagramSocket* DatagramSocket::waitForNextConnection() const
int DatagramSocket::getBoundPort() const noexcept
{
while (waitUntilReady (true, -1) == 1)
{
struct sockaddr_storage address;
juce_socklen_t len = sizeof (address);
char buf[1];
if (recvfrom (handle, buf, 0, 0, (struct sockaddr*) &address, &len) > 0)
return new DatagramSocket (inet_ntoa (((struct sockaddr_in*) &address)->sin_addr),
ntohs (((struct sockaddr_in*) &address)->sin_port),
-1, -1);
}
return nullptr;
return isBound ? SocketHelpers::getBoundPort (handle) : -1;
}
//==============================================================================
int DatagramSocket::waitUntilReady (const bool readyForReading,
const int timeoutMsecs) const
{
return connected ? SocketHelpers::waitForReadiness (handle, readyForReading, timeoutMsecs)
: -1;
return SocketHelpers::waitForReadiness (handle, readLock, readyForReading, timeoutMsecs);
}
int DatagramSocket::read (void* destBuffer, const int maxBytesToRead, const bool blockUntilSpecifiedAmountHasArrived)
int DatagramSocket::read (void* destBuffer, int maxBytesToRead, bool shouldBlock)
{
return connected ? SocketHelpers::readSocket (handle, destBuffer, maxBytesToRead,
connected, blockUntilSpecifiedAmountHasArrived)
: -1;
bool connected = true;
return isBound ? SocketHelpers::readSocket (handle, destBuffer, maxBytesToRead,
connected, shouldBlock, readLock) : -1;
}
int DatagramSocket::write (const void* sourceBuffer, const int numBytesToWrite)
int DatagramSocket::read (void* destBuffer, int maxBytesToRead, bool shouldBlock, String& senderIPAddress, int& senderPort)
{
// You need to call connect() first to set the server address..
jassert (serverAddress != nullptr && connected);
bool connected = true;
return isBound ? SocketHelpers::readSocket (handle, destBuffer, maxBytesToRead, connected,
shouldBlock, readLock, &senderIPAddress, &senderPort) : -1;
}
return connected ? (int) sendto (handle, (const char*) sourceBuffer,
(size_t) numBytesToWrite, 0,
static_cast <const struct addrinfo*> (serverAddress)->ai_addr,
(juce_socklen_t) static_cast <const struct addrinfo*> (serverAddress)->ai_addrlen)
: -1;
int DatagramSocket::write (const String& remoteHostname, int remotePortNumber,
const void* sourceBuffer, int numBytesToWrite)
{
struct addrinfo*& info = reinterpret_cast <struct addrinfo*&> (lastServerAddress);
// getaddrinfo can be quite slow so cache the result of the address lookup
if (info == nullptr || remoteHostname != lastServerHost || remotePortNumber != lastServerPort)
{
if (info != nullptr)
freeaddrinfo (info);
if ((info = SocketHelpers::getAddressInfo (true, remoteHostname, remotePortNumber)) == nullptr)
return -1;
lastServerHost = remoteHostname;
lastServerPort = remotePortNumber;
}
return (int) ::sendto (handle, (const char*) sourceBuffer,
(juce_socklen_t) numBytesToWrite, 0,
info->ai_addr, (socklen_t) info->ai_addrlen);
}
bool DatagramSocket::isLocal() const noexcept
bool DatagramSocket::joinMulticast (const String& multicastIPAddress)
{
return hostName == "127.0.0.1";
if (! isBound)
return false;
return SocketHelpers::multicast (handle, multicastIPAddress, lastBindAddress, true);
}
bool DatagramSocket::leaveMulticast (const String& multicastIPAddress)
{
if (! isBound)
return false;
return SocketHelpers::multicast (handle, multicastIPAddress, lastBindAddress, false);
}
#if JUCE_MSVC


+ 74
- 44
source/modules/juce_core/network/juce_Socket.h View File

@@ -65,6 +65,25 @@ public:
*/
bool bindToPort (int localPortNumber);
/** Binds the socket to the specified local port and local address.
If localAddress is not an empty string then the socket will be bound to localAddress
as well. This is useful if you would like to bind your socket to a specific network
adapter. Note that localAddress must be an IP address assigned to one of your
network address otherwise this function will fail.
@returns true on success; false may indicate that another socket is already bound
on the same port
@see bindToPort(int localPortNumber), IPAddress::findAllAddresses
*/
bool bindToPort (int localPortNumber, const String& localAddress);
/** Returns the local port number to which this socket is currently bound.
This is useful if you need to know to which port the OS has actually bound your
socket when calling the constructor or bindToPort with zero as the
localPortNumber argument. Returns -1 if the function fails. */
int getBoundPort() const noexcept;
/** Tries to connect the socket to hostname:port.
If timeOutMillisecs is 0, then this method will block until the operating system
@@ -164,6 +183,7 @@ private:
String hostName;
int volatile portNumber, handle;
bool connected, isListener;
mutable CriticalSection readLock;
StreamingSocket (const String& hostname, int portNumber, int handle);
@@ -185,22 +205,16 @@ class JUCE_API DatagramSocket
public:
//==============================================================================
/**
Creates an (uninitialised) datagram socket.
Creates a datagram socket.
The localPortNumber is the port on which to bind this socket. If this value is 0,
the port number is assigned by the operating system.
To use the socket for sending, call the connect() method. This will not immediately
make a connection, but will save the destination you've provided. After this, you can
call read() or write().
You first need to bind this socket to a port with bindToPort if you intend to read
from this socket.
If enableBroadcasting is true, the socket will be allowed to send broadcast messages
(may require extra privileges on linux)
To wait for other sockets to connect to this one, call waitForNextConnection().
*/
DatagramSocket (int localPortNumber,
bool enableBroadcasting = false);
DatagramSocket (bool enableBroadcasting = false);
/** Destructor. */
~DatagramSocket();
@@ -208,37 +222,33 @@ public:
//==============================================================================
/** Binds the socket to the specified local port.
The localPortNumber is the port on which to bind this socket. If this value is 0,
the port number is assigned by the operating system.
@returns true on success; false may indicate that another socket is already bound
on the same port
*/
bool bindToPort (int localPortNumber);
/** Tries to connect the socket to hostname:port.
If timeOutMillisecs is 0, then this method will block until the operating system
rejects the connection (which could take a long time).
/** Binds the socket to the specified local port and local address.
@returns true if it succeeds.
@see isConnected
If localAddress is not an empty string then the socket will be bound to localAddress
as well. This is useful if you would like to bind your socket to a specific network
adapter. Note that localAddress must be an IP address assigned to one of your
network address otherwise this function will fail.
@returns true on success; false may indicate that another socket is already bound
on the same port
@see bindToPort(int localPortNumber), IPAddress::findAllAddresses
*/
bool connect (const String& remoteHostname,
int remotePortNumber,
int timeOutMillisecs = 3000);
bool bindToPort (int localPortNumber, const String& localAddress);
/** True if the socket is currently connected. */
bool isConnected() const noexcept { return connected; }
/** Returns the local port number to which this socket is currently bound.
/** Closes the connection. */
void close();
/** Returns the name of the currently connected host. */
const String& getHostName() const noexcept { return hostName; }
/** Returns the port number that's currently open. */
int getPort() const noexcept { return portNumber; }
This is useful if you need to know to which port the OS has actually bound your
socket when bindToPort was called with zero.
/** True if the socket is connected to this machine rather than over the network. */
bool isLocal() const noexcept;
Returns -1 if the socket didn't bind to any port yet or an error occured. */
int getBoundPort() const noexcept;
/** Returns the OS's socket handle that's currently open. */
int getRawSocketHandle() const noexcept { return handle; }
@@ -271,6 +281,21 @@ public:
int read (void* destBuffer, int maxBytesToRead,
bool blockUntilSpecifiedAmountHasArrived);
/** Reads bytes from the socket and return the IP address of the sender.
If blockUntilSpecifiedAmountHasArrived is true, the method will block until
maxBytesToRead bytes have been read, (or until an error occurs). If this
flag is false, the method will return as much data as is currently available
without blocking.
@returns the number of bytes read, or -1 if there was an error. On a successful
result, the senderIPAddress value will be set to the IP of the sender.
@see waitUntilReady
*/
int read (void* destBuffer, int maxBytesToRead,
bool blockUntilSpecifiedAmountHasArrived,
String& senderIPAddress, int& senderPortNumber);
/** Writes bytes to the socket from a buffer.
Note that this method will block unless you have checked the socket is ready
@@ -278,25 +303,30 @@ public:
@returns the number of bytes written, or -1 if there was an error.
*/
int write (const void* sourceBuffer, int numBytesToWrite);
int write (const String& remoteHostname, int remotePortNumber,
const void* sourceBuffer, int numBytesToWrite);
//==============================================================================
/** This waits for incoming data to be sent, and returns a socket that can be used
to read it.
/** Join a multicast group
@returns true if it succeeds.
*/
bool joinMulticast (const String& multicastIPAddress);
The object that gets returned is owned by the caller, and can't be used for
sending, but can be used to read the data.
/** Leave a multicast group
@returns true if it succeeds.
*/
DatagramSocket* waitForNextConnection() const;
bool leaveMulticast (const String& multicastIPAddress);
private:
//==============================================================================
String hostName;
int volatile portNumber, handle;
bool connected, allowBroadcast;
void* serverAddress;
DatagramSocket (const String& hostname, int portNumber, int handle, int localPortNumber);
int handle;
bool isBound;
String lastBindAddress, lastServerHost;
int lastServerPort;
void* lastServerAddress;
mutable CriticalSection readLock;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (DatagramSocket)
};


+ 1
- 1
source/modules/juce_core/streams/juce_MemoryOutputStream.h View File

@@ -111,7 +111,7 @@ public:
capacity off the block, so that its length matches the amount of actual data that
has been written so far.
*/
void flush();
void flush() override;
bool write (const void*, size_t) override;
int64 getPosition() override { return (int64) position; }


+ 6
- 3
source/modules/juce_core/system/juce_SystemStats.cpp View File

@@ -67,7 +67,8 @@ struct CPUInformation
{
CPUInformation() noexcept
: numCpus (0), hasMMX (false), hasSSE (false),
hasSSE2 (false), hasSSE3 (false), has3DNow (false)
hasSSE2 (false), hasSSE3 (false), has3DNow (false),
hasSSSE3 (false), hasAVX (false)
{
initialise();
}
@@ -75,7 +76,7 @@ struct CPUInformation
void initialise() noexcept;
int numCpus;
bool hasMMX, hasSSE, hasSSE2, hasSSE3, has3DNow;
bool hasMMX, hasSSE, hasSSE2, hasSSE3, has3DNow, hasSSSE3, hasAVX;
};
static const CPUInformation& getCPUInformation() noexcept
@@ -86,10 +87,12 @@ static const CPUInformation& getCPUInformation() noexcept
int SystemStats::getNumCpus() noexcept { return getCPUInformation().numCpus; }
bool SystemStats::hasMMX() noexcept { return getCPUInformation().hasMMX; }
bool SystemStats::has3DNow() noexcept { return getCPUInformation().has3DNow; }
bool SystemStats::hasSSE() noexcept { return getCPUInformation().hasSSE; }
bool SystemStats::hasSSE2() noexcept { return getCPUInformation().hasSSE2; }
bool SystemStats::hasSSE3() noexcept { return getCPUInformation().hasSSE3; }
bool SystemStats::has3DNow() noexcept { return getCPUInformation().has3DNow; }
bool SystemStats::hasSSSE3() noexcept { return getCPUInformation().hasSSSE3; }
bool SystemStats::hasAVX() noexcept { return getCPUInformation().hasAVX; }
//==============================================================================


+ 28
- 24
source/modules/juce_core/system/juce_SystemStats.h View File

@@ -47,29 +47,31 @@ public:
/** The set of possible results of the getOperatingSystemType() method. */
enum OperatingSystemType
{
UnknownOS = 0,
Linux = 0x2000,
Android = 0x3000,
iOS = 0x8000,
MacOSX_10_4 = 0x1004,
MacOSX_10_5 = 0x1005,
MacOSX_10_6 = 0x1006,
MacOSX_10_7 = 0x1007,
MacOSX_10_8 = 0x1008,
MacOSX_10_9 = 0x1009,
MacOSX_10_10 = 0x100a,
Win2000 = 0x4105,
WinXP = 0x4106,
WinVista = 0x4107,
Windows7 = 0x4108,
Windows8_0 = 0x4109,
Windows8_1 = 0x410a,
Windows = 0x4000, /**< To test whether any version of Windows is running,
you can use the expression ((getOperatingSystemType() & Windows) != 0). */
UnknownOS = 0,
MacOSX = 0x0100, /**< To test whether any version of OSX is running,
you can use the expression ((getOperatingSystemType() & MacOSX) != 0). */
Windows = 0x0200, /**< To test whether any version of Windows is running,
you can use the expression ((getOperatingSystemType() & Windows) != 0). */
Linux = 0x0400,
Android = 0x0800,
iOS = 0x1000,
MacOSX_10_4 = MacOSX | 4,
MacOSX_10_5 = MacOSX | 5,
MacOSX_10_6 = MacOSX | 6,
MacOSX_10_7 = MacOSX | 7,
MacOSX_10_8 = MacOSX | 8,
MacOSX_10_9 = MacOSX | 9,
MacOSX_10_10 = MacOSX | 10,
Win2000 = Windows | 1,
WinXP = Windows | 2,
WinVista = Windows | 3,
Windows7 = Windows | 4,
Windows8_0 = Windows | 5,
Windows8_1 = Windows | 6,
Windows10 = Windows | 7
};
/** Returns the type of operating system we're running on.
@@ -150,10 +152,12 @@ public:
static String getCpuVendor();
static bool hasMMX() noexcept; /**< Returns true if Intel MMX instructions are available. */
static bool has3DNow() noexcept; /**< Returns true if AMD 3DNOW instructions are available. */
static bool hasSSE() noexcept; /**< Returns true if Intel SSE instructions are available. */
static bool hasSSE2() noexcept; /**< Returns true if Intel SSE2 instructions are available. */
static bool hasSSE3() noexcept; /**< Returns true if Intel SSE2 instructions are available. */
static bool has3DNow() noexcept; /**< Returns true if AMD 3DNOW instructions are available. */
static bool hasSSSE3() noexcept; /**< Returns true if Intel SSSE3 instructions are available. */
static bool hasAVX() noexcept; /**< Returns true if Intel AVX instructions are available. */
//==============================================================================
/** Finds out how much RAM is in the machine.


+ 1
- 1
source/modules/juce_core/text/juce_CharPointer_UTF8.h View File

@@ -511,7 +511,7 @@ public:
if (byte < 0)
{
uint8 bit = 0x40;
int bit = 0x40;
int numExtraValues = 0;
while ((byte & bit) != 0)


+ 8
- 8
source/modules/juce_core/text/juce_CharacterFunctions.cpp View File

@@ -34,18 +34,18 @@
juce_wchar CharacterFunctions::toUpperCase (const juce_wchar character) noexcept
{
return towupper ((wchar_t) character);
return (juce_wchar) towupper ((wint_t) character);
}
juce_wchar CharacterFunctions::toLowerCase (const juce_wchar character) noexcept
{
return towlower ((wchar_t) character);
return (juce_wchar) towlower ((wint_t) character);
}
bool CharacterFunctions::isUpperCase (const juce_wchar character) noexcept
{
#if JUCE_WINDOWS
return iswupper ((wchar_t) character) != 0;
return iswupper ((wint_t) character) != 0;
#else
return toLowerCase (character) != character;
#endif
@@ -54,7 +54,7 @@ bool CharacterFunctions::isUpperCase (const juce_wchar character) noexcept
bool CharacterFunctions::isLowerCase (const juce_wchar character) noexcept
{
#if JUCE_WINDOWS
return iswlower ((wchar_t) character) != 0;
return iswlower ((wint_t) character) != 0;
#else
return toUpperCase (character) != character;
#endif
@@ -72,7 +72,7 @@ bool CharacterFunctions::isWhitespace (const char character) noexcept
bool CharacterFunctions::isWhitespace (const juce_wchar character) noexcept
{
return iswspace ((wchar_t) character) != 0;
return iswspace ((wint_t) character) != 0;
}
bool CharacterFunctions::isDigit (const char character) noexcept
@@ -82,7 +82,7 @@ bool CharacterFunctions::isDigit (const char character) noexcept
bool CharacterFunctions::isDigit (const juce_wchar character) noexcept
{
return iswdigit ((wchar_t) character) != 0;
return iswdigit ((wint_t) character) != 0;
}
bool CharacterFunctions::isLetter (const char character) noexcept
@@ -93,7 +93,7 @@ bool CharacterFunctions::isLetter (const char character) noexcept
bool CharacterFunctions::isLetter (const juce_wchar character) noexcept
{
return iswalpha ((wchar_t) character) != 0;
return iswalpha ((wint_t) character) != 0;
}
bool CharacterFunctions::isLetterOrDigit (const char character) noexcept
@@ -105,7 +105,7 @@ bool CharacterFunctions::isLetterOrDigit (const char character) noexcept
bool CharacterFunctions::isLetterOrDigit (const juce_wchar character) noexcept
{
return iswalnum ((wchar_t) character) != 0;
return iswalnum ((wint_t) character) != 0;
}
int CharacterFunctions::getHexDigitValue (const juce_wchar digit) noexcept


+ 6
- 9
source/modules/juce_core/text/juce_Identifier.cpp View File

@@ -40,25 +40,22 @@ Identifier& Identifier::operator= (const Identifier other) noexcept
Identifier::Identifier (const String& nm)
: name (StringPool::getGlobalPool().getPooledString (nm))
{
/* An Identifier string must be suitable for use as a script variable or XML
attribute, so it can only contain this limited set of characters.. */
jassert (isValidIdentifier (toString()));
// An Identifier cannot be created from an empty string!
jassert (nm.isNotEmpty());
}
Identifier::Identifier (const char* nm)
: name (StringPool::getGlobalPool().getPooledString (nm))
{
/* An Identifier string must be suitable for use as a script variable or XML
attribute, so it can only contain this limited set of characters.. */
jassert (isValidIdentifier (toString()));
// An Identifier cannot be created from an empty string!
jassert (nm != nullptr && nm[0] != 0);
}
Identifier::Identifier (String::CharPointerType start, String::CharPointerType end)
: name (StringPool::getGlobalPool().getPooledString (start, end))
{
/* An Identifier string must be suitable for use as a script variable or XML
attribute, so it can only contain this limited set of characters.. */
jassert (isValidIdentifier (toString()));
// An Identifier cannot be created from an empty string!
jassert (start < end);
}
Identifier Identifier::null;


+ 5
- 6
source/modules/juce_core/text/juce_String.cpp View File

@@ -1617,10 +1617,10 @@ String String::upToLastOccurrenceOf (StringRef sub,
bool String::isQuotedString() const
{
const String trimmed (trimStart());
const juce_wchar trimmedStart = trimStart()[0];
return trimmed[0] == '"'
|| trimmed[0] == '\'';
return trimmedStart == '"'
|| trimmedStart == '\'';
}
String String::unquoted() const
@@ -2522,14 +2522,13 @@ public:
beginTest ("var");
var v1 = 0;
var v2 = 0.1;
var v3 = "0.1";
var v2 = 0.16;
var v3 = "0.16";
var v4 = (int64) 0;
var v5 = 0.0;
expect (! v2.equals (v1));
expect (! v1.equals (v2));
expect (v2.equals (v3));
expect (v3.equals (v2));
expect (! v3.equals (v1));
expect (! v1.equals (v3));
expect (v1.equals (v4));


+ 2
- 2
source/modules/juce_core/text/juce_String.h View File

@@ -299,13 +299,13 @@ public:
Note that there's also an isNotEmpty() method to help write readable code.
@see containsNonWhitespaceChars()
*/
inline bool isEmpty() const noexcept { return text[0] == 0; }
inline bool isEmpty() const noexcept { return text.isEmpty(); }
/** Returns true if the string contains at least one character.
Note that there's also an isEmpty() method to help write readable code.
@see containsNonWhitespaceChars()
*/
inline bool isNotEmpty() const noexcept { return text[0] != 0; }
inline bool isNotEmpty() const noexcept { return ! text.isEmpty(); }
/** Resets this string to be empty. */
void clear() noexcept;


+ 1
- 1
source/modules/juce_core/threads/juce_Thread.h View File

@@ -235,7 +235,7 @@ public:
/** Finds the thread object that is currently running.
Note that the main UI thread (or other non-Juce threads) don't have a Thread
object associated with them, so this will return 0.
object associated with them, so this will return nullptr.
*/
static Thread* JUCE_CALLTYPE getCurrentThread();


+ 1
- 1
source/modules/juce_core/xml/juce_XmlElement.h View File

@@ -352,7 +352,7 @@ public:
/** Returns the value of a named attribute as floating-point.
This will try to find the attribute and convert it to an integer (using
This will try to find the attribute and convert it to a double (using
the String::getDoubleValue() method).
@param attributeName the name of the attribute to look up


+ 1
- 1
source/modules/juce_core/zip/juce_GZIPCompressorOutputStream.h View File

@@ -72,7 +72,7 @@ public:
the stream is closed - this means that no more data can be written to it, and any
subsequent attempts to call write() will cause an assertion.
*/
void flush();
void flush() override;
int64 getPosition() override;
bool setPosition (int64) override;


+ 23
- 12
source/modules/juce_core/zip/juce_GZIPDecompressorInputStream.cpp View File

@@ -90,7 +90,7 @@ namespace zlibNamespace
class GZIPDecompressorInputStream::GZIPDecompressHelper
{
public:
GZIPDecompressHelper (const bool dontWrap)
GZIPDecompressHelper (Format f)
: finished (true),
needsDictionary (false),
error (true),
@@ -100,7 +100,7 @@ public:
{
using namespace zlibNamespace;
zerostruct (stream);
streamIsValid = (inflateInit2 (&stream, dontWrap ? -MAX_WBITS : MAX_WBITS) == Z_OK);
streamIsValid = (inflateInit2 (&stream, getBitsForFormat (f)) == Z_OK);
finished = error = ! streamIsValid;
}
@@ -157,6 +157,19 @@ public:
return 0;
}
static int getBitsForFormat (Format f) noexcept
{
switch (f)
{
case zlibFormat: return MAX_WBITS;
case deflateFormat: return -MAX_WBITS;
case gzipFormat: return MAX_WBITS | 16;
default: jassertfalse; break;
}
return MAX_WBITS;
}
bool finished, needsDictionary, error, streamIsValid;
enum { gzipDecompBufferSize = 32768 };
@@ -170,32 +183,30 @@ private:
};
//==============================================================================
GZIPDecompressorInputStream::GZIPDecompressorInputStream (InputStream* const source,
const bool deleteSourceWhenDestroyed,
const bool noWrap_,
const int64 uncompressedStreamLength_)
GZIPDecompressorInputStream::GZIPDecompressorInputStream (InputStream* source, bool deleteSourceWhenDestroyed,
Format f, int64 uncompressedLength)
: sourceStream (source, deleteSourceWhenDestroyed),
uncompressedStreamLength (uncompressedStreamLength_),
noWrap (noWrap_),
uncompressedStreamLength (uncompressedLength),
format (f),
isEof (false),
activeBufferSize (0),
originalSourcePos (source->getPosition()),
currentPos (0),
buffer ((size_t) GZIPDecompressHelper::gzipDecompBufferSize),
helper (new GZIPDecompressHelper (noWrap_))
helper (new GZIPDecompressHelper (f))
{
}
GZIPDecompressorInputStream::GZIPDecompressorInputStream (InputStream& source)
: sourceStream (&source, false),
uncompressedStreamLength (-1),
noWrap (false),
format (zlibFormat),
isEof (false),
activeBufferSize (0),
originalSourcePos (source.getPosition()),
currentPos (0),
buffer ((size_t) GZIPDecompressHelper::gzipDecompBufferSize),
helper (new GZIPDecompressHelper (false))
helper (new GZIPDecompressHelper (zlibFormat))
{
}
@@ -278,7 +289,7 @@ bool GZIPDecompressorInputStream::setPosition (int64 newPos)
isEof = false;
activeBufferSize = 0;
currentPos = 0;
helper = new GZIPDecompressHelper (noWrap);
helper = new GZIPDecompressHelper (format);
sourceStream->setPosition (originalSourcePos);
}


+ 16
- 4
source/modules/juce_core/zip/juce_GZIPDecompressorInputStream.h View File

@@ -43,21 +43,28 @@
class JUCE_API GZIPDecompressorInputStream : public InputStream
{
public:
enum Format
{
zlibFormat = 0,
deflateFormat,
gzipFormat
};
//==============================================================================
/** Creates a decompressor stream.
@param sourceStream the stream to read from
@param deleteSourceWhenDestroyed whether or not to delete the source stream
when this object is destroyed
@param noWrap this is used internally by the ZipFile class
and should be ignored by user applications
@param sourceFormat can be used to select which of the supported
formats the data is expected to be in
@param uncompressedStreamLength if the creator knows the length that the
uncompressed stream will be, then it can supply this
value, which will be returned by getTotalLength()
*/
GZIPDecompressorInputStream (InputStream* sourceStream,
bool deleteSourceWhenDestroyed,
bool noWrap = false,
Format sourceFormat = zlibFormat,
int64 uncompressedStreamLength = -1);
/** Creates a decompressor stream.
@@ -81,7 +88,7 @@ private:
//==============================================================================
OptionalScopedPointer<InputStream> sourceStream;
const int64 uncompressedStreamLength;
const bool noWrap;
const Format format;
bool isEof;
int activeBufferSize;
int64 originalSourcePos, currentPos;
@@ -91,6 +98,11 @@ private:
friend struct ContainerDeletePolicy<GZIPDecompressHelper>;
ScopedPointer<GZIPDecompressHelper> helper;
#if JUCE_CATCH_DEPRECATED_CODE_MISUSE
// The arguments to this method have changed! Please pass a Format enum instead of the old dontWrap bool.
GZIPDecompressorInputStream (InputStream*, bool, bool, int64 x = -1);
#endif
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (GZIPDecompressorInputStream)
};


+ 3
- 1
source/modules/juce_core/zip/juce_ZipFile.cpp View File

@@ -298,7 +298,9 @@ InputStream* ZipFile::createStreamForEntry (const int index)
if (zei->compressed)
{
stream = new GZIPDecompressorInputStream (stream, true, true, (int64) zei->entry.uncompressedSize);
stream = new GZIPDecompressorInputStream (stream, true,
GZIPDecompressorInputStream::deflateFormat,
(int64) zei->entry.uncompressedSize);
// (much faster to unzip in big blocks using a buffer..)
stream = new BufferedInputStream (stream, 32768, true);


+ 16
- 16
source/modules/juce_core/zip/zlib/trees.c View File

@@ -571,7 +571,7 @@ local void gen_codes (ct_data *tree, /* the tree to decorate */
ushf *bl_count) /* number of codes at each bit length */
{
ush next_code[MAX_BITS+1]; /* next code value for each bit length */
ush code = 0; /* running code value */
ush code_ = 0; /* running code value */
int bits; /* bit index */
int n; /* code index */
@@ -579,12 +579,12 @@ local void gen_codes (ct_data *tree, /* the tree to decorate */
* without bit reversal.
*/
for (bits = 1; bits <= MAX_BITS; bits++) {
next_code[bits] = code = (code + bl_count[bits-1]) << 1;
next_code[bits] = code_ = (code_ + bl_count[bits-1]) << 1;
}
/* Check that the bit counts in bl_count are consistent. The last code
* must be all ones.
*/
Assert (code + bl_count[MAX_BITS]-1 == (1<<MAX_BITS)-1,
Assert (code_ + bl_count[MAX_BITS]-1 == (1<<MAX_BITS)-1,
"inconsistent bit counts");
Tracev((stderr,"\ngen_codes: max_code %d ", max_code));
@@ -1055,7 +1055,7 @@ local void compress_block (deflate_state *s,
unsigned dist; /* distance of matched string */
int lc; /* match length or unmatched char (if dist == 0) */
unsigned lx = 0; /* running index in l_buf */
unsigned code; /* the code to send */
unsigned code_; /* the code to send */
int extra; /* number of extra bits to send */
if (s->last_lit != 0) do {
@@ -1066,21 +1066,21 @@ local void compress_block (deflate_state *s,
Tracecv(isgraph(lc), (stderr," '%c' ", lc));
} else {
/* Here, lc is the match length - MIN_MATCH */
code = _length_code[lc];
send_code(s, code+LITERALS+1, ltree); /* send the length code */
extra = extra_lbits[code];
code_ = _length_code[lc];
send_code(s, code_+LITERALS+1, ltree); /* send the length code */
extra = extra_lbits[code_];
if (extra != 0) {
lc -= base_length[code];
lc -= base_length[code_];
send_bits(s, lc, extra); /* send the extra length bits */
}
dist--; /* dist is now the match distance - 1 */
code = d_code(dist);
Assert (code < D_CODES, "bad d_code");
code_ = d_code(dist);
Assert (code_ < D_CODES, "bad d_code");
send_code(s, code, dtree); /* send the distance code */
extra = extra_dbits[code];
send_code(s, code_, dtree); /* send the distance code */
extra = extra_dbits[code_];
if (extra != 0) {
dist -= base_dist[code];
dist -= base_dist[code_];
send_bits(s, dist, extra); /* send the extra distance bits */
}
} /* literal or match pair ? */
@@ -1120,12 +1120,12 @@ local void set_data_type (deflate_state *s)
* method would use a table)
* IN assertion: 1 <= len <= 15
*/
local unsigned bi_reverse (unsigned code, int len)
local unsigned bi_reverse (unsigned code_, int len)
{
register unsigned res = 0;
do {
res |= code & 1;
code >>= 1, res <<= 1;
res |= code_ & 1;
code_ >>= 1, res <<= 1;
} while (--len > 0);
return res >> 1;
}


+ 1
- 1
source/modules/juce_data_structures/app_properties/juce_PropertiesFile.h View File

@@ -223,7 +223,7 @@ public:
protected:
/** @internal */
virtual void propertyChanged();
void propertyChanged() override;
private:
//==============================================================================


+ 8
- 0
source/modules/juce_data_structures/undomanager/juce_UndoManager.cpp View File

@@ -203,6 +203,14 @@ void UndoManager::setCurrentTransactionName (const String& newName) noexcept
action->name = newName;
}
String UndoManager::getCurrentTransactionName() const noexcept
{
if (ActionSet* action = getCurrentSet())
return action->name;
return newTransactionName;
}
//==============================================================================
UndoManager::ActionSet* UndoManager::getCurrentSet() const noexcept { return transactions [nextIndex - 1]; }
UndoManager::ActionSet* UndoManager::getNextSet() const noexcept { return transactions [nextIndex]; }


+ 5
- 0
source/modules/juce_data_structures/undomanager/juce_UndoManager.h View File

@@ -144,6 +144,11 @@ public:
*/
void setCurrentTransactionName (const String& newName) noexcept;
/** Returns the name of the current transaction.
@see setCurrentTransactionName
*/
String getCurrentTransactionName() const noexcept;
//==============================================================================
/** Returns true if there's at least one action in the list to undo.
@see getUndoDescription, undo, canRedo


+ 2
- 2
source/modules/juce_data_structures/values/juce_Value.cpp View File

@@ -72,12 +72,12 @@ public:
{
}
var getValue() const
var getValue() const override
{
return value;
}
void setValue (const var& newValue)
void setValue (const var& newValue) override
{
if (! newValue.equalsWithSameType (value))
{


+ 15
- 5
source/modules/juce_data_structures/values/juce_ValueTree.cpp View File

@@ -814,8 +814,8 @@ public:
tree.removeListener (this);
}
var getValue() const { return tree [property]; }
void setValue (const var& newValue) { tree.setProperty (property, newValue, undoManager); }
var getValue() const override { return tree [property]; }
void setValue (const var& newValue) override { tree.setProperty (property, newValue, undoManager); }
private:
ValueTree tree;
@@ -1003,9 +1003,16 @@ ValueTree ValueTree::readFromStream (InputStream& input)
for (int i = 0; i < numProps; ++i)
{
const String name (input.readString());
jassert (name.isNotEmpty());
const var value (var::readFromStream (input));
v.object->properties.set (name, value);
if (name.isNotEmpty())
{
const var value (var::readFromStream (input));
v.object->properties.set (name, value);
}
else
{
jassertfalse; // trying to read corrupted data!
}
}
const int numChildren = input.readCompressedInt();
@@ -1015,6 +1022,9 @@ ValueTree ValueTree::readFromStream (InputStream& input)
{
ValueTree child (readFromStream (input));
if (! child.isValid())
return v;
v.object->children.add (child.object);
child.object->parent = v.object;
}


+ 1
- 1
source/modules/juce_events/messages/juce_ApplicationBase.cpp View File

@@ -232,7 +232,7 @@ int JUCEApplicationBase::main()
jassert (app != nullptr);
if (! app->initialiseApp())
return app->getApplicationReturnValue();
return app->shutdownApp();
JUCE_TRY
{


+ 1
- 2
source/modules/juce_events/messages/juce_ApplicationBase.h View File

@@ -259,6 +259,7 @@ public:
static CreateInstanceFunction createInstance;
virtual bool initialiseApp();
int shutdownApp();
static void JUCE_CALLTYPE sendUnhandledException (const std::exception*, const char* sourceFile, int lineNumber);
bool sendCommandLineToPreexistingInstance();
#endif
@@ -274,8 +275,6 @@ private:
friend struct ContainerDeletePolicy<MultipleInstanceHandler>;
ScopedPointer<MultipleInstanceHandler> multipleInstanceHandler;
int shutdownApp();
JUCE_DECLARE_NON_COPYABLE (JUCEApplicationBase)
};


+ 11
- 1
source/modules/juce_events/native/juce_ios_MessageManager.mm View File

@@ -25,7 +25,15 @@
void MessageManager::runDispatchLoop()
{
jassert (isThisTheMessageThread()); // must only be called by the message thread
runDispatchLoopUntil (-1);
while (! quitMessagePosted)
{
JUCE_AUTORELEASEPOOL
{
[[NSRunLoop currentRunLoop] runMode: NSDefaultRunLoopMode
beforeDate: [NSDate dateWithTimeIntervalSinceNow: 0.001]];
}
}
}
void MessageManager::stopDispatchLoop()
@@ -34,6 +42,7 @@ void MessageManager::stopDispatchLoop()
exit (0); // iOS apps get no mercy..
}
#if JUCE_MODAL_LOOPS_PERMITTED
bool MessageManager::runDispatchLoopUntil (int millisecondsToRunFor)
{
JUCE_AUTORELEASEPOOL
@@ -59,6 +68,7 @@ bool MessageManager::runDispatchLoopUntil (int millisecondsToRunFor)
return ! quitMessagePosted;
}
}
#endif
//==============================================================================
static ScopedPointer<MessageQueue> messageQueue;


+ 4
- 2
source/modules/juce_events/native/juce_linux_Messaging.cpp View File

@@ -74,7 +74,7 @@ public:
ScopedUnlock ul (lock);
const unsigned char x = 0xff;
size_t bytesWritten = write (fd[0], &x, 1);
ssize_t bytesWritten = write (fd[0], &x, 1);
(void) bytesWritten;
}
}
@@ -186,7 +186,7 @@ private:
const ScopedUnlock ul (lock);
unsigned char x;
size_t numBytes = read (fd[1], &x, 1);
ssize_t numBytes = read (fd[1], &x, 1);
(void) numBytes;
}
@@ -235,6 +235,8 @@ namespace LinuxErrorHandling
int errorHandler (Display* display, XErrorEvent* event)
{
(void) display; (void) event;
#if JUCE_DEBUG_XERRORS
char errorStr[64] = { 0 };
char requestStr[64] = { 0 };


+ 4
- 2
source/modules/juce_events/native/juce_mac_MessageManager.mm View File

@@ -261,11 +261,13 @@ static void shutdownNSApp()
void MessageManager::stopDispatchLoop()
{
#if JUCE_PROJUCER_LIVE_BUILD
quitMessagePosted = true;
#else
#if ! JUCE_PROJUCER_LIVE_BUILD
if (isThisTheMessageThread())
{
quitMessagePosted = true;
shutdownNSApp();
}
else
@@ -273,7 +275,7 @@ void MessageManager::stopDispatchLoop()
struct QuitCallback : public CallbackMessage
{
QuitCallback() {}
void messageCallback() override { shutdownNSApp(); }
void messageCallback() override { MessageManager::getInstance()->stopDispatchLoop(); }
};
(new QuitCallback())->post();


+ 41
- 41
source/modules/juce_events/timers/juce_Timer.cpp View File

@@ -112,10 +112,10 @@ public:
{
const LockType::ScopedLockType sl (lock);
while (firstTimer != nullptr && firstTimer->countdownMs <= 0)
while (firstTimer != nullptr && firstTimer->timerCountdownMs <= 0)
{
Timer* const t = firstTimer;
t->countdownMs = t->periodMs;
t->timerCountdownMs = t->timerPeriodMs;
removeTimer (t);
addTimer (t);
@@ -169,11 +169,11 @@ public:
{
if (instance != nullptr)
{
tim->countdownMs = newCounter;
tim->periodMs = newCounter;
tim->timerCountdownMs = newCounter;
tim->timerPeriodMs = newCounter;
if ((tim->next != nullptr && tim->next->countdownMs < tim->countdownMs)
|| (tim->previous != nullptr && tim->previous->countdownMs > tim->countdownMs))
if ((tim->nextTimer != nullptr && tim->nextTimer->timerCountdownMs < tim->timerCountdownMs)
|| (tim->previousTimer != nullptr && tim->previousTimer->timerCountdownMs > tim->timerCountdownMs))
{
instance->removeTimer (tim);
instance->addTimer (tim);
@@ -210,28 +210,28 @@ private:
Timer* i = firstTimer;
if (i == nullptr || i->countdownMs > t->countdownMs)
if (i == nullptr || i->timerCountdownMs > t->timerCountdownMs)
{
t->next = firstTimer;
t->nextTimer = firstTimer;
firstTimer = t;
}
else
{
while (i->next != nullptr && i->next->countdownMs <= t->countdownMs)
i = i->next;
while (i->nextTimer != nullptr && i->nextTimer->timerCountdownMs <= t->timerCountdownMs)
i = i->nextTimer;
jassert (i != nullptr);
t->next = i->next;
t->previous = i;
i->next = t;
t->nextTimer = i->nextTimer;
t->previousTimer = i;
i->nextTimer = t;
}
if (t->next != nullptr)
t->next->previous = t;
if (t->nextTimer != nullptr)
t->nextTimer->previousTimer = t;
jassert ((t->next == nullptr || t->next->countdownMs >= t->countdownMs)
&& (t->previous == nullptr || t->previous->countdownMs <= t->countdownMs));
jassert ((t->nextTimer == nullptr || t->nextTimer->timerCountdownMs >= t->timerCountdownMs)
&& (t->previousTimer == nullptr || t->previousTimer->timerCountdownMs <= t->timerCountdownMs));
notify();
}
@@ -244,32 +244,32 @@ private:
jassert (timerExists (t));
#endif
if (t->previous != nullptr)
if (t->previousTimer != nullptr)
{
jassert (firstTimer != t);
t->previous->next = t->next;
t->previousTimer->nextTimer = t->nextTimer;
}
else
{
jassert (firstTimer == t);
firstTimer = t->next;
firstTimer = t->nextTimer;
}
if (t->next != nullptr)
t->next->previous = t->previous;
if (t->nextTimer != nullptr)
t->nextTimer->previousTimer = t->previousTimer;
t->next = nullptr;
t->previous = nullptr;
t->nextTimer = nullptr;
t->previousTimer = nullptr;
}
int getTimeUntilFirstTimer (const int numMillisecsElapsed) const
{
const LockType::ScopedLockType sl (lock);
for (Timer* t = firstTimer; t != nullptr; t = t->next)
t->countdownMs -= numMillisecsElapsed;
for (Timer* t = firstTimer; t != nullptr; t = t->nextTimer)
t->timerCountdownMs -= numMillisecsElapsed;
return firstTimer != nullptr ? firstTimer->countdownMs : 1000;
return firstTimer != nullptr ? firstTimer->timerCountdownMs : 1000;
}
void handleAsyncUpdate() override
@@ -280,7 +280,7 @@ private:
#if JUCE_DEBUG
bool timerExists (Timer* const t) const noexcept
{
for (Timer* tt = firstTimer; tt != nullptr; tt = tt->next)
for (Timer* tt = firstTimer; tt != nullptr; tt = tt->nextTimer)
if (tt == t)
return true;
@@ -296,18 +296,18 @@ Timer::TimerThread::LockType Timer::TimerThread::lock;
//==============================================================================
Timer::Timer() noexcept
: countdownMs (0),
periodMs (0),
previous (nullptr),
next (nullptr)
: timerCountdownMs (0),
timerPeriodMs (0),
previousTimer (nullptr),
nextTimer (nullptr)
{
}
Timer::Timer (const Timer&) noexcept
: countdownMs (0),
periodMs (0),
previous (nullptr),
next (nullptr)
: timerCountdownMs (0),
timerPeriodMs (0),
previousTimer (nullptr),
nextTimer (nullptr)
{
}
@@ -320,10 +320,10 @@ void Timer::startTimer (const int interval) noexcept
{
const TimerThread::LockType::ScopedLockType sl (TimerThread::lock);
if (periodMs == 0)
if (timerPeriodMs == 0)
{
countdownMs = interval;
periodMs = jmax (1, interval);
timerCountdownMs = interval;
timerPeriodMs = jmax (1, interval);
TimerThread::add (this);
}
else
@@ -344,10 +344,10 @@ void Timer::stopTimer() noexcept
{
const TimerThread::LockType::ScopedLockType sl (TimerThread::lock);
if (periodMs > 0)
if (timerPeriodMs > 0)
{
TimerThread::remove (this);
periodMs = 0;
timerPeriodMs = 0;
}
}


+ 8
- 10
source/modules/juce_events/timers/juce_Timer.h View File

@@ -54,7 +54,6 @@ class JUCE_API Timer
protected:
//==============================================================================
/** Creates a Timer.
When created, the timer is stopped, so use startTimer() to get it going.
*/
Timer() noexcept;
@@ -64,7 +63,7 @@ protected:
Note that this timer won't be started, even if the one you're copying
is running.
*/
Timer (const Timer& other) noexcept;
Timer (const Timer&) noexcept;
public:
//==============================================================================
@@ -86,8 +85,8 @@ public:
time between calling this method and the next timer callback
will not be less than the interval length passed in.
@param intervalInMilliseconds the interval to use (any values less than 1 will be
rounded up to 1)
@param intervalInMilliseconds the interval to use (any value less
than 1 will be rounded up to 1)
*/
void startTimer (int intervalInMilliseconds) noexcept;
@@ -108,12 +107,12 @@ public:
//==============================================================================
/** Returns true if the timer is currently running. */
bool isTimerRunning() const noexcept { return periodMs > 0; }
bool isTimerRunning() const noexcept { return timerPeriodMs > 0; }
/** Returns the timer's interval.
@returns the timer's interval in milliseconds if it's running, or 0 if it's not.
*/
int getTimerInterval() const noexcept { return periodMs; }
int getTimerInterval() const noexcept { return timerPeriodMs; }
//==============================================================================
@@ -125,11 +124,10 @@ public:
private:
class TimerThread;
friend class TimerThread;
int countdownMs, periodMs;
Timer* previous;
Timer* next;
int timerCountdownMs, timerPeriodMs; // NB: these member variable names are a little verbose
Timer* previousTimer, *nextTimer; // to reduce risk of name-clashes with user subclasses
Timer& operator= (const Timer&);
Timer& operator= (const Timer&) JUCE_DELETED_FUNCTION;
};
#endif // JUCE_TIMER_H_INCLUDED

+ 28
- 11
source/modules/juce_graphics/colour/juce_Colour.cpp View File

@@ -136,7 +136,7 @@ namespace ColourHelpers
//==============================================================================
Colour::Colour() noexcept
: argb (0)
: argb (0, 0, 0, 0)
{
}
@@ -151,11 +151,12 @@ Colour& Colour::operator= (const Colour& other) noexcept
return *this;
}
bool Colour::operator== (const Colour& other) const noexcept { return argb.getARGB() == other.argb.getARGB(); }
bool Colour::operator!= (const Colour& other) const noexcept { return argb.getARGB() != other.argb.getARGB(); }
bool Colour::operator== (const Colour& other) const noexcept { return argb.getNativeARGB() == other.argb.getNativeARGB(); }
bool Colour::operator!= (const Colour& other) const noexcept { return argb.getNativeARGB() != other.argb.getNativeARGB(); }
//==============================================================================
Colour::Colour (const uint32 col) noexcept : argb (col)
Colour::Colour (const uint32 col) noexcept
: argb ((col >> 24) & 0xff, (col >> 16) & 0xff, (col >> 8) & 0xff, col & 0xff)
{
}
@@ -206,10 +207,26 @@ Colour::Colour (const float hue, const float saturation, const float brightness,
{
}
Colour::Colour (PixelARGB argb_) noexcept
: argb (argb_)
{
}
Colour::Colour (PixelRGB rgb) noexcept
: argb (Colour (rgb.getInARGBMaskOrder()).argb)
{
}
Colour::Colour (PixelAlpha alpha) noexcept
: argb (Colour (alpha.getInARGBMaskOrder()).argb)
{
}
Colour::~Colour() noexcept
{
}
//==============================================================================
const PixelARGB Colour::getPixelARGB() const noexcept
{
@@ -220,7 +237,7 @@ const PixelARGB Colour::getPixelARGB() const noexcept
uint32 Colour::getARGB() const noexcept
{
return argb.getARGB();
return argb.getInARGBMaskOrder();
}
//==============================================================================
@@ -238,7 +255,7 @@ Colour Colour::withAlpha (const uint8 newAlpha) const noexcept
{
PixelARGB newCol (argb);
newCol.setAlpha (newAlpha);
return Colour (newCol.getARGB());
return Colour (newCol);
}
Colour Colour::withAlpha (const float newAlpha) const noexcept
@@ -247,7 +264,7 @@ Colour Colour::withAlpha (const float newAlpha) const noexcept
PixelARGB newCol (argb);
newCol.setAlpha (ColourHelpers::floatToUInt8 (newAlpha));
return Colour (newCol.getARGB());
return Colour (newCol);
}
Colour Colour::withMultipliedAlpha (const float alphaMultiplier) const noexcept
@@ -256,7 +273,7 @@ Colour Colour::withMultipliedAlpha (const float alphaMultiplier) const noexcept
PixelARGB newCol (argb);
newCol.setAlpha ((uint8) jmin (0xff, roundToInt (alphaMultiplier * newCol.getAlpha())));
return Colour (newCol.getARGB());
return Colour (newCol);
}
//==============================================================================
@@ -294,7 +311,7 @@ Colour Colour::interpolatedWith (Colour other, float proportionOfOther) const no
c1.tween (c2, (uint32) roundToInt (proportionOfOther * 255.0f));
c1.unpremultiply();
return Colour (c1.getARGB());
return Colour (c1);
}
//==============================================================================
@@ -428,7 +445,7 @@ Colour Colour::contrasting (Colour colour1,
//==============================================================================
String Colour::toString() const
{
return String::toHexString ((int) argb.getARGB());
return String::toHexString ((int) argb.getInARGBMaskOrder());
}
Colour Colour::fromString (StringRef encodedColourString)
@@ -438,7 +455,7 @@ Colour Colour::fromString (StringRef encodedColourString)
String Colour::toDisplayString (const bool includeAlphaValue) const
{
return String::toHexString ((int) (argb.getARGB() & (includeAlphaValue ? 0xffffffff : 0xffffff)))
return String::toHexString ((int) (argb.getInARGBMaskOrder() & (includeAlphaValue ? 0xffffffff : 0xffffff)))
.paddedLeft ('0', includeAlphaValue ? 8 : 6)
.toUpperCase();
}

+ 13
- 0
source/modules/juce_graphics/colour/juce_Colour.h View File

@@ -115,6 +115,19 @@ public:
float brightness,
float alpha) noexcept;
/** Creates a colour using a PixelARGB object. This function assumes that the argb pixel is
not premultiplied.
*/
Colour (PixelARGB argb) noexcept;
/** Creates a colour using a PixelRGB object.
*/
Colour (PixelRGB rgb) noexcept;
/** Creates a colour using a PixelAlpha object.
*/
Colour (PixelAlpha alpha) noexcept;
/** Creates a colour using floating point hue, saturation and brightness values, and an 8-bit alpha.
The floating point values must be between 0.0 and 1.0.


+ 306
- 154
source/modules/juce_graphics/colour/juce_PixelFormats.h View File

@@ -46,7 +46,7 @@ inline uint32 clampPixelComponents (uint32 x) noexcept
//==============================================================================
/**
Represents a 32-bit ARGB pixel with premultiplied alpha, and can perform compositing
Represents a 32-bit INTERNAL pixel with premultiplied alpha, and can perform compositing
operations with it.
This is used internally by the imaging classes.
@@ -60,13 +60,6 @@ public:
PixelARGB() noexcept {}
~PixelARGB() noexcept {}
/** Creates a pixel from a 32-bit argb value.
*/
PixelARGB (const uint32 argbValue) noexcept
: argb (argbValue)
{
}
PixelARGB (const uint8 a, const uint8 r, const uint8 g, const uint8 b) noexcept
{
components.b = b;
@@ -75,30 +68,81 @@ public:
components.a = a;
}
forcedinline uint32 getARGB() const noexcept { return argb; }
forcedinline uint32 getUnpremultipliedARGB() const noexcept { PixelARGB p (argb); p.unpremultiply(); return p.getARGB(); }
//==============================================================================
/** Returns a uint32 which represents the pixel in a platform dependent format. */
forcedinline uint32 getNativeARGB() const noexcept { return internal; }
/** Returns a uint32 which will be in argb order as if constructed with the following mask operation
((alpha << 24) | (red << 16) | (green << 8) | blue). */
forcedinline uint32 getInARGBMaskOrder() const noexcept
{
#if JUCE_ANDROID
return (uint32) ((components.a << 24) | (components.r << 16) | (components.g << 8) | (components.b << 0));
#else
return getNativeARGB();
#endif
}
/** Returns a uint32 which when written to memory, will be in the order a, r, g, b. In other words,
if the return-value is read as a uint8 array then the elements will be in the order of a, r, g, b*/
inline uint32 getInARGBMemoryOrder() const noexcept
{
#if JUCE_BIG_ENDIAN
return getInARGBMaskOrder();
#else
return (uint32) ((components.b << 24) | (components.g << 16) | (components.r << 8) | components.a);
#endif
}
/** Return channels with an even index and insert zero bytes between them. This is useful for blending
operations. The exact channels which are returned is platform dependent. */
forcedinline uint32 getEvenBytes() const noexcept { return 0x00ff00ff & internal; }
forcedinline uint32 getRB() const noexcept { return 0x00ff00ff & argb; }
forcedinline uint32 getAG() const noexcept { return 0x00ff00ff & (argb >> 8); }
/** Return channels with an odd index and insert zero bytes between them. This is useful for blending
operations. The exact channels which are returned is platform dependent. */
forcedinline uint32 getOddBytes() const noexcept { return 0x00ff00ff & (internal >> 8); }
forcedinline uint8 getAlpha() const noexcept { return components.a; }
forcedinline uint8 getRed() const noexcept { return components.r; }
forcedinline uint8 getGreen() const noexcept { return components.g; }
forcedinline uint8 getBlue() const noexcept { return components.b; }
//==============================================================================
forcedinline uint8 getAlpha() const noexcept { return components.a; }
forcedinline uint8 getRed() const noexcept { return components.r; }
forcedinline uint8 getGreen() const noexcept { return components.g; }
forcedinline uint8 getBlue() const noexcept { return components.b; }
#if JUCE_GCC && ! JUCE_CLANG
// NB these are here as a workaround because GCC refuses to bind to packed values.
forcedinline uint8& getAlpha() noexcept { return comps [indexA]; }
forcedinline uint8& getRed() noexcept { return comps [indexR]; }
forcedinline uint8& getGreen() noexcept { return comps [indexG]; }
forcedinline uint8& getBlue() noexcept { return comps [indexB]; }
forcedinline uint8& getAlpha() noexcept { return comps [indexA]; }
forcedinline uint8& getRed() noexcept { return comps [indexR]; }
forcedinline uint8& getGreen() noexcept { return comps [indexG]; }
forcedinline uint8& getBlue() noexcept { return comps [indexB]; }
#else
forcedinline uint8& getAlpha() noexcept { return components.a; }
forcedinline uint8& getRed() noexcept { return components.r; }
forcedinline uint8& getGreen() noexcept { return components.g; }
forcedinline uint8& getBlue() noexcept { return components.b; }
forcedinline uint8& getAlpha() noexcept { return components.a; }
forcedinline uint8& getRed() noexcept { return components.r; }
forcedinline uint8& getGreen() noexcept { return components.g; }
forcedinline uint8& getBlue() noexcept { return components.b; }
#endif
//==============================================================================
/** Copies another pixel colour over this one.
This doesn't blend it - this colour is simply replaced by the other one.
*/
template <class Pixel>
forcedinline void set (const Pixel& src) noexcept
{
internal = src.getNativeARGB();
}
//==============================================================================
/** Sets the pixel's colour from individual components. */
void setARGB (const uint8 a, const uint8 r, const uint8 g, const uint8 b) noexcept
{
components.b = b;
components.g = g;
components.r = r;
components.a = a;
}
//==============================================================================
/** Blends another pixel onto this one.
This takes into account the opacity of the pixel being overlaid, and blends
@@ -107,10 +151,15 @@ public:
template <class Pixel>
forcedinline void blend (const Pixel& src) noexcept
{
const uint32 alpha = 0x100 - src.getAlpha();
uint32 rb = src.getRB() + maskPixelComponents (getRB() * alpha);
uint32 ag = src.getAG() + maskPixelComponents (getAG() * alpha);
argb = clampPixelComponents (rb) + (clampPixelComponents (ag) << 8);
uint32 rb = src.getEvenBytes();
uint32 ag = src.getOddBytes();
const uint32 alpha = 0x100 - (ag >> 16);
rb += maskPixelComponents (getEvenBytes() * alpha);
ag += maskPixelComponents (getOddBytes() * alpha);
internal = clampPixelComponents (rb) | (clampPixelComponents (ag) << 8);
}
/** Blends another pixel onto this one.
@@ -129,14 +178,15 @@ public:
template <class Pixel>
forcedinline void blend (const Pixel& src, uint32 extraAlpha) noexcept
{
uint32 ag = maskPixelComponents (extraAlpha * src.getAG());
uint32 rb = maskPixelComponents (extraAlpha * src.getEvenBytes());
uint32 ag = maskPixelComponents (extraAlpha * src.getOddBytes());
const uint32 alpha = 0x100 - (ag >> 16);
ag += maskPixelComponents (getAG() * alpha);
uint32 rb = maskPixelComponents (extraAlpha * src.getRB())
+ maskPixelComponents (getRB() * alpha);
rb += maskPixelComponents (getEvenBytes() * alpha);
ag += maskPixelComponents (getOddBytes() * alpha);
argb = clampPixelComponents(rb) + (clampPixelComponents (ag) << 8);
internal = clampPixelComponents (rb) | (clampPixelComponents (ag) << 8);
}
/** Blends another pixel with this one, creating a colour that is somewhere
@@ -145,29 +195,20 @@ public:
template <class Pixel>
forcedinline void tween (const Pixel& src, const uint32 amount) noexcept
{
uint32 drb = getRB();
drb += (((src.getRB() - drb) * amount) >> 8);
drb &= 0x00ff00ff;
uint32 dag = getAG();
dag += (((src.getAG() - dag) * amount) >> 8);
dag &= 0x00ff00ff;
dag <<= 8;
uint32 dEvenBytes = getEvenBytes();
dEvenBytes += (((src.getEvenBytes() - dEvenBytes) * amount) >> 8);
dEvenBytes &= 0x00ff00ff;
dag |= drb;
argb = dag;
}
uint32 dOddBytes = getOddBytes();
dOddBytes += (((src.getOddBytes() - dOddBytes) * amount) >> 8);
dOddBytes &= 0x00ff00ff;
dOddBytes <<= 8;
/** Copies another pixel colour over this one.
This doesn't blend it - this colour is simply replaced by the other one.
*/
template <class Pixel>
forcedinline void set (const Pixel& src) noexcept
{
argb = src.getARGB();
dOddBytes |= dEvenBytes;
internal = dOddBytes;
}
//==============================================================================
/** Replaces the colour's alpha value with another one. */
forcedinline void setAlpha (const uint8 newAlpha) noexcept
{
@@ -177,10 +218,12 @@ public:
/** Multiplies the colour's alpha value with another one. */
forcedinline void multiplyAlpha (int multiplier) noexcept
{
// increment alpha by 1, so that if multiplier == 255 (full alpha),
// this function will not change the values.
++multiplier;
argb = ((((uint32) multiplier) * getAG()) & 0xff00ff00)
| (((((uint32) multiplier) * getRB()) >> 8) & 0x00ff00ff);
internal = ((((uint32) multiplier) * getOddBytes()) & 0xff00ff00)
| (((((uint32) multiplier) * getEvenBytes()) >> 8) & 0x00ff00ff);
}
forcedinline void multiplyAlpha (const float multiplier) noexcept
@@ -188,14 +231,8 @@ public:
multiplyAlpha ((int) (multiplier * 255.0f));
}
/** Sets the pixel's colour from individual components. */
void setARGB (const uint8 a, const uint8 r, const uint8 g, const uint8 b) noexcept
{
components.b = b;
components.g = g;
components.r = r;
components.a = a;
}
inline PixelARGB getUnpremultiplied() const noexcept { PixelARGB p (internal); p.unpremultiply(); return p; }
/** Premultiplies the pixel's RGB values by its alpha. */
forcedinline void premultiply() noexcept
@@ -234,9 +271,9 @@ public:
}
else
{
components.b = (uint8) jmin ((uint32) 0xff, (components.b * 0xff) / alpha);
components.g = (uint8) jmin ((uint32) 0xff, (components.g * 0xff) / alpha);
components.r = (uint8) jmin ((uint32) 0xff, (components.r * 0xff) / alpha);
components.b = (uint8) jmin ((uint32) 0xffu, (components.b * 0xffu) / alpha);
components.g = (uint8) jmin ((uint32) 0xffu, (components.g * 0xffu) / alpha);
components.r = (uint8) jmin ((uint32) 0xffu, (components.r * 0xffu) / alpha);
}
}
}
@@ -257,41 +294,53 @@ public:
}
}
/** Returns a uint32 which when written to memory, will be in the order r, g, b, a. */
inline uint32 getInRGBAMemoryOrder() const noexcept
{
#if JUCE_BIG_ENDIAN
return (((uint32) components.r) << 24) | (((uint32) components.g) << 16) | (((uint32) components.b) << 8) | components.a;
#else
return (((uint32) components.a) << 24) | (((uint32) components.b) << 16) | (((uint32) components.g) << 8) | components.r;
#endif
}
//==============================================================================
/** The indexes of the different components in the byte layout of this type of colour. */
#if JUCE_ANDROID
#if JUCE_BIG_ENDIAN
enum { indexA = 0, indexR = 3, indexG = 2, indexB = 1 };
#else
enum { indexA = 3, indexR = 0, indexG = 1, indexB = 2 };
#endif
#else
#if JUCE_BIG_ENDIAN
enum { indexA = 0, indexR = 1, indexG = 2, indexB = 3 };
#else
enum { indexA = 3, indexR = 2, indexG = 1, indexB = 0 };
#endif
#endif
private:
//==============================================================================
PixelARGB (const uint32 internalValue) noexcept
: internal (internalValue)
{
}
//==============================================================================
struct Components
{
#if JUCE_ANDROID
#if JUCE_BIG_ENDIAN
uint8 a, b, g, r;
#else
uint8 r, g, b, a;
#endif
#else
#if JUCE_BIG_ENDIAN
uint8 a, r, g, b;
#else
uint8 b, g, r, a;
#endif
#endif
} JUCE_PACKED;
union
{
uint32 argb;
uint32 internal;
Components components;
#if JUCE_GCC
uint8 comps[4];
uint8 comps[4]; // helper struct needed because gcc does not allow references to packed union members
#endif
};
}
@@ -316,23 +365,64 @@ public:
PixelRGB() noexcept {}
~PixelRGB() noexcept {}
/** Creates a pixel from a 32-bit argb value.
//==============================================================================
/** Returns a uint32 which represents the pixel in a platform dependent format which is compatible
with the native format of a PixelARGB.
(The argb format is that used by PixelARGB)
*/
PixelRGB (const uint32 argb) noexcept
@see PixelARGB::getNativeARGB */
forcedinline uint32 getNativeARGB() const noexcept
{
#if JUCE_ANDROID
return (uint32) ((0xff << 24) | r | (g << 8) | (b << 16));
#else
return (uint32) ((0xff << 24) | b | (g << 8) | (r << 16));
#endif
}
/** Returns a uint32 which will be in argb order as if constructed with the following mask operation
((alpha << 24) | (red << 16) | (green << 8) | blue). */
forcedinline uint32 getInARGBMaskOrder() const noexcept
{
#if JUCE_ANDROID
return (uint32) ((0xff << 24) | (r << 16) | (g << 8) | (b << 0));
#else
return getNativeARGB();
#endif
}
/** Returns a uint32 which when written to memory, will be in the order a, r, g, b. In other words,
if the return-value is read as a uint8 array then the elements will be in the order of a, r, g, b*/
inline uint32 getInARGBMemoryOrder() const noexcept
{
r = (uint8) (argb >> 16);
g = (uint8) (argb >> 8);
b = (uint8) (argb);
#if JUCE_BIG_ENDIAN
return getInARGBMaskOrder();
#else
return (uint32) ((b << 24) | (g << 16) | (r << 8) | 0xff);
#endif
}
forcedinline uint32 getARGB() const noexcept { return 0xff000000 | b | (((uint32) g) << 8) | (((uint32) r) << 16); }
forcedinline uint32 getUnpremultipliedARGB() const noexcept { return getARGB(); }
/** Return channels with an even index and insert zero bytes between them. This is useful for blending
operations. The exact channels which are returned is platform dependent but compatible with the
return value of getEvenBytes of the PixelARGB class.
forcedinline uint32 getRB() const noexcept { return b | (uint32) (r << 16); }
forcedinline uint32 getAG() const noexcept { return (uint32) (0xff0000 | g); }
@see PixelARGB::getEvenBytes */
forcedinline uint32 getEvenBytes() const noexcept
{
#if JUCE_ANDROID
return (uint32) (r | (b << 16));
#else
return (uint32) (b | (r << 16));
#endif
}
/** Return channels with an odd index and insert zero bytes between them. This is useful for blending
operations. The exact channels which are returned is platform dependent but compatible with the
return value of getOddBytes of the PixelARGB class.
@see PixelARGB::getOddBytes */
forcedinline uint32 getOddBytes() const noexcept { return (uint32)0xff0000 | g; }
//==============================================================================
forcedinline uint8 getAlpha() const noexcept { return 0xff; }
forcedinline uint8 getRed() const noexcept { return r; }
forcedinline uint8 getGreen() const noexcept { return g; }
@@ -342,6 +432,30 @@ public:
forcedinline uint8& getGreen() noexcept { return g; }
forcedinline uint8& getBlue() noexcept { return b; }
//==============================================================================
/** Copies another pixel colour over this one.
This doesn't blend it - this colour is simply replaced by the other one.
Because PixelRGB has no alpha channel, any alpha value in the source pixel
is thrown away.
*/
template <class Pixel>
forcedinline void set (const Pixel& src) noexcept
{
b = src.getBlue();
g = src.getGreen();
r = src.getRed();
}
/** Sets the pixel's colour from individual components. */
void setARGB (const uint8, const uint8 red, const uint8 green, const uint8 blue) noexcept
{
r = red;
g = green;
b = blue;
}
//==============================================================================
/** Blends another pixel onto this one.
This takes into account the opacity of the pixel being overlaid, and blends
@@ -350,14 +464,22 @@ public:
template <class Pixel>
forcedinline void blend (const Pixel& src) noexcept
{
const uint32 alpha = 0x100 - src.getAlpha();
const uint32 alpha = (uint32) (0x100 - src.getAlpha());
// getEvenBytes returns 0x00rr00bb on non-android
uint32 rb = clampPixelComponents (src.getEvenBytes() + maskPixelComponents (getEvenBytes() * alpha));
// getOddBytes returns 0x00aa00gg on non-android
uint32 ag = clampPixelComponents (src.getOddBytes() + ((g * alpha) >> 8));
uint32 rb = clampPixelComponents (src.getRB() + maskPixelComponents (getRB() * alpha));
uint32 ag = src.getAG() + (g * alpha >> 8);
g = (uint8) (ag & 0xff);
#if JUCE_ANDROID
b = (uint8) (rb >> 16);
r = (uint8) (rb & 0xff);
#else
r = (uint8) (rb >> 16);
g = (uint8) clampPixelComponents (ag);
b = (uint8) rb;
b = (uint8) (rb & 0xff);
#endif
}
forcedinline void blend (const PixelRGB src) noexcept
@@ -373,16 +495,23 @@ public:
template <class Pixel>
forcedinline void blend (const Pixel& src, uint32 extraAlpha) noexcept
{
uint32 ag = maskPixelComponents (extraAlpha * src.getAG());
uint32 ag = maskPixelComponents (extraAlpha * src.getOddBytes());
uint32 rb = maskPixelComponents (extraAlpha * src.getEvenBytes());
const uint32 alpha = 0x100 - (ag >> 16);
ag += g * alpha >> 8;
uint32 rb = clampPixelComponents (maskPixelComponents (extraAlpha * src.getRB())
+ maskPixelComponents (getRB() * alpha));
ag = clampPixelComponents (ag + (g * alpha >> 8));
rb = clampPixelComponents (rb + maskPixelComponents (getEvenBytes() * alpha));
g = (uint8) (ag & 0xff);
b = (uint8) rb;
g = (uint8) clampPixelComponents (ag);
#if JUCE_ANDROID
b = (uint8) (rb >> 16);
r = (uint8) (rb & 0xff);
#else
r = (uint8) (rb >> 16);
b = (uint8) (rb & 0xff);
#endif
}
/** Blends another pixel with this one, creating a colour that is somewhere
@@ -391,31 +520,24 @@ public:
template <class Pixel>
forcedinline void tween (const Pixel& src, const uint32 amount) noexcept
{
uint32 drb = getRB();
drb += (((src.getRB() - drb) * amount) >> 8);
uint32 dEvenBytes = getEvenBytes();
dEvenBytes += (((src.getEvenBytes() - dEvenBytes) * amount) >> 8);
uint32 dag = getAG();
dag += (((src.getAG() - dag) * amount) >> 8);
uint32 dOddBytes = getOddBytes();
dOddBytes += (((src.getOddBytes() - dOddBytes) * amount) >> 8);
b = (uint8) drb;
g = (uint8) dag;
r = (uint8) (drb >> 16);
}
g = (uint8) (dOddBytes & 0xff); // dOddBytes = 0x00aa00gg
/** Copies another pixel colour over this one.
This doesn't blend it - this colour is simply replaced by the other one.
Because PixelRGB has no alpha channel, any alpha value in the source pixel
is thrown away.
*/
template <class Pixel>
forcedinline void set (const Pixel& src) noexcept
{
b = src.getBlue();
g = src.getGreen();
r = src.getRed();
#if JUCE_ANDROID
r = (uint8) (dEvenBytes & 0xff); // dEvenBytes = 0x00bb00rr
b = (uint8) (dEvenBytes >> 16);
#else
b = (uint8) (dEvenBytes & 0xff); // dEvenBytes = 0x00rr00bb
r = (uint8) (dEvenBytes >> 16);
#endif
}
//==============================================================================
/** This method is included for compatibility with the PixelARGB class. */
forcedinline void setAlpha (const uint8) noexcept {}
@@ -425,14 +547,6 @@ public:
/** Multiplies the colour's alpha value with another one. */
forcedinline void multiplyAlpha (float) noexcept {}
/** Sets the pixel's colour from individual components. */
void setARGB (const uint8, const uint8 red, const uint8 green, const uint8 blue) noexcept
{
r = red;
g = green;
b = blue;
}
/** Premultiplies the pixel's RGB values by its alpha. */
forcedinline void premultiply() noexcept {}
@@ -454,6 +568,20 @@ public:
private:
//==============================================================================
PixelRGB (const uint32 internal) noexcept
{
#if JUCE_ANDROID
b = (uint8) (internal >> 16);
g = (uint8) (internal >> 8);
r = (uint8) (internal);
#else
r = (uint8) (internal >> 16);
g = (uint8) (internal >> 8);
b = (uint8) (internal);
#endif
}
//==============================================================================
#if JUCE_MAC
uint8 r, g, b;
#else
@@ -486,21 +614,36 @@ public:
PixelAlpha() noexcept {}
~PixelAlpha() noexcept {}
/** Creates a pixel from a 32-bit argb value.
//==============================================================================
/** Returns a uint32 which represents the pixel in a platform dependent format which is compatible
with the native format of a PixelARGB.
(The argb format is that used by PixelARGB)
*/
PixelAlpha (const uint32 argb) noexcept
{
a = (uint8) (argb >> 24);
}
@see PixelARGB::getNativeARGB */
forcedinline uint32 getNativeARGB() const noexcept { return (uint32) ((a << 24) | (a << 16) | (a << 8) | a); }
forcedinline uint32 getARGB() const noexcept { return (((uint32) a) << 24) | (((uint32) a) << 16) | (((uint32) a) << 8) | a; }
forcedinline uint32 getUnpremultipliedARGB() const noexcept { return (((uint32) a) << 24) | 0xffffff; }
/** Returns a uint32 which will be in argb order as if constructed with the following mask operation
((alpha << 24) | (red << 16) | (green << 8) | blue). */
forcedinline uint32 getInARGBMaskOrder() const noexcept { return getNativeARGB(); }
forcedinline uint32 getRB() const noexcept { return (((uint32) a) << 16) | a; }
forcedinline uint32 getAG() const noexcept { return (((uint32) a) << 16) | a; }
/** Returns a uint32 which when written to memory, will be in the order a, r, g, b. In other words,
if the return-value is read as a uint8 array then the elements will be in the order of a, r, g, b*/
inline uint32 getInARGBMemoryOrder() const noexcept { return getNativeARGB(); }
/** Return channels with an even index and insert zero bytes between them. This is useful for blending
operations. The exact channels which are returned is platform dependent but compatible with the
return value of getEvenBytes of the PixelARGB class.
@see PixelARGB::getEvenBytes */
forcedinline uint32 getEvenBytes() const noexcept { return (uint32) ((a << 16) | a); }
/** Return channels with an odd index and insert zero bytes between them. This is useful for blending
operations. The exact channels which are returned is platform dependent but compatible with the
return value of getOddBytes of the PixelARGB class.
@see PixelARGB::getOddBytes */
forcedinline uint32 getOddBytes() const noexcept { return (uint32) ((a << 16) | a); }
//==============================================================================
forcedinline uint8 getAlpha() const noexcept { return a; }
forcedinline uint8& getAlpha() noexcept { return a; }
@@ -508,6 +651,24 @@ public:
forcedinline uint8 getGreen() const noexcept { return 0; }
forcedinline uint8 getBlue() const noexcept { return 0; }
//==============================================================================
/** Copies another pixel colour over this one.
This doesn't blend it - this colour is simply replaced by the other one.
*/
template <class Pixel>
forcedinline void set (const Pixel& src) noexcept
{
a = src.getAlpha();
}
/** Sets the pixel's colour from individual components. */
forcedinline void setARGB (const uint8 a_, const uint8 /*r*/, const uint8 /*g*/, const uint8 /*b*/) noexcept
{
a = a_;
}
//==============================================================================
/** Blends another pixel onto this one.
This takes into account the opacity of the pixel being overlaid, and blends
@@ -542,16 +703,7 @@ public:
a += ((src.getAlpha() - a) * amount) >> 8;
}
/** Copies another pixel colour over this one.
This doesn't blend it - this colour is simply replaced by the other one.
*/
template <class Pixel>
forcedinline void set (const Pixel& src) noexcept
{
a = src.getAlpha();
}
//==============================================================================
/** Replaces the colour's alpha value with another one. */
forcedinline void setAlpha (const uint8 newAlpha) noexcept
{
@@ -570,12 +722,6 @@ public:
a = (uint8) (a * multiplier);
}
/** Sets the pixel's colour from individual components. */
forcedinline void setARGB (const uint8 a_, const uint8 /*r*/, const uint8 /*g*/, const uint8 /*b*/) noexcept
{
a = a_;
}
/** Premultiplies the pixel's RGB values by its alpha. */
forcedinline void premultiply() noexcept {}
@@ -589,6 +735,12 @@ public:
enum { indexA = 0 };
private:
//==============================================================================
PixelAlpha (const uint32 internal) noexcept
{
a = (uint8) (internal >> 24);
}
//==============================================================================
uint8 a;
}


+ 12
- 4
source/modules/juce_graphics/contexts/juce_GraphicsContext.h View File

@@ -203,7 +203,7 @@ public:
The minimumHorizontalScale parameter specifies how much the text can be squashed horizontally
to try to squeeze it into the space. If you don't want any horizontal scaling to occur, you
can set this value to 1.0f.
can set this value to 1.0f. Pass 0 if you want it to use a default value.
@see GlyphArrangement::addFittedText
*/
@@ -211,7 +211,7 @@ public:
int x, int y, int width, int height,
Justification justificationFlags,
int maximumNumberOfLines,
float minimumHorizontalScale = 0.7f) const;
float minimumHorizontalScale = 0.0f) const;
/** Tries to draw a text string inside a given space.
@@ -228,7 +228,7 @@ public:
The minimumHorizontalScale parameter specifies how much the text can be squashed horizontally
to try to squeeze it into the space. If you don't want any horizontal scaling to occur, you
can set this value to 1.0f.
can set this value to 1.0f. Pass 0 if you want it to use a default value.
@see GlyphArrangement::addFittedText
*/
@@ -236,7 +236,7 @@ public:
const Rectangle<int>& area,
Justification justificationFlags,
int maximumNumberOfLines,
float minimumHorizontalScale = 0.7f) const;
float minimumHorizontalScale = 0.0f) const;
//==============================================================================
/** Fills the context's entire clip region with the current colour or brush.
@@ -374,21 +374,29 @@ public:
//==============================================================================
/** Draws a line between two points.
The line is 1 pixel wide and drawn with the current colour or brush.
TIP: If you're trying to draw horizontal or vertical lines, don't use this -
it's better to use fillRect() instead unless you really need an angled line.
*/
void drawLine (float startX, float startY, float endX, float endY) const;
/** Draws a line between two points with a given thickness.
TIP: If you're trying to draw horizontal or vertical lines, don't use this -
it's better to use fillRect() instead unless you really need an angled line.
@see Path::addLineSegment
*/
void drawLine (float startX, float startY, float endX, float endY, float lineThickness) const;
/** Draws a line between two points.
The line is 1 pixel wide and drawn with the current colour or brush.
TIP: If you're trying to draw horizontal or vertical lines, don't use this -
it's better to use fillRect() instead unless you really need an angled line.
*/
void drawLine (const Line<float>& line) const;
/** Draws a line between two points with a given thickness.
@see Path::addLineSegment
TIP: If you're trying to draw horizontal or vertical lines, don't use this -
it's better to use fillRect() instead unless you really need an angled line.
*/
void drawLine (const Line<float>& line, float lineThickness) const;


+ 2
- 2
source/modules/juce_graphics/contexts/juce_LowLevelGraphicsPostScriptRenderer.cpp View File

@@ -433,11 +433,11 @@ void LowLevelGraphicsPostScriptRenderer::writeImage (const Image& im,
{
PixelARGB p (*(const PixelARGB*) pixelData);
p.unpremultiply();
pixel = Colours::white.overlaidWith (Colour (p.getARGB()));
pixel = Colours::white.overlaidWith (Colour (p));
}
else if (im.isRGB())
{
pixel = Colour (((const PixelRGB*) pixelData)->getARGB());
pixel = Colour (*((const PixelRGB*) pixelData));
}
else
{


+ 4
- 0
source/modules/juce_graphics/fonts/juce_Font.cpp View File

@@ -30,6 +30,7 @@ namespace FontValues
}
const float defaultFontHeight = 14.0f;
float minimumHorizontalScale = 0.7f;
String fallbackFont;
String fallbackFontStyle;
}
@@ -37,6 +38,9 @@ namespace FontValues
typedef Typeface::Ptr (*GetTypefaceForFont) (const Font&);
GetTypefaceForFont juce_getTypefaceForFont = nullptr;
float Font::getDefaultMinimumHorizontalScaleFactor() noexcept { return FontValues::minimumHorizontalScale; }
void Font::setDefaultMinimumHorizontalScaleFactor (float newValue) noexcept { FontValues::minimumHorizontalScale = newValue; }
//==============================================================================
class TypefaceCache : private DeletedAtShutdown
{


+ 12
- 0
source/modules/juce_graphics/fonts/juce_Font.h View File

@@ -319,6 +319,18 @@ public:
*/
void setHorizontalScale (float scaleFactor);
/** Returns the minimum horizontal scale to which fonts may be squashed when trying to
create a layout.
@see setDefaultMinimumHorizontalScaleFactor
*/
static float getDefaultMinimumHorizontalScaleFactor() noexcept;
/** Sets the minimum horizontal scale to which fonts may be squashed when trying to
create a text layout.
@see getDefaultMinimumHorizontalScaleFactor
*/
static void setDefaultMinimumHorizontalScaleFactor (float newMinimumScaleFactor) noexcept;
/** Returns the font's kerning.
This is the extra space added between adjacent characters, as a proportion


+ 4
- 1
source/modules/juce_graphics/fonts/juce_GlyphArrangement.cpp View File

@@ -366,8 +366,11 @@ void GlyphArrangement::addFittedText (const Font& f,
const float width, const float height,
Justification layout,
int maximumLines,
const float minimumHorizontalScale)
float minimumHorizontalScale)
{
if (minimumHorizontalScale == 0.0f)
minimumHorizontalScale = Font::getDefaultMinimumHorizontalScaleFactor();
// doesn't make much sense if this is outside a sensible range of 0.5 to 1.0
jassert (minimumHorizontalScale > 0 && minimumHorizontalScale <= 1.0f);


+ 5
- 1
source/modules/juce_graphics/fonts/juce_GlyphArrangement.h View File

@@ -208,6 +208,10 @@ public:
A Justification parameter lets you specify how the text is laid out within the rectangle,
both horizontally and vertically.
The minimumHorizontalScale parameter specifies how much the text can be squashed horizontally
to try to squeeze it into the space. If you don't want any horizontal scaling to occur, you
can set this value to 1.0f. Pass 0 if you want it to use the default value.
@see Graphics::drawFittedText
*/
void addFittedText (const Font& font,
@@ -215,7 +219,7 @@ public:
float x, float y, float width, float height,
Justification layout,
int maximumLinesToUse,
float minimumHorizontalScale = 0.7f);
float minimumHorizontalScale = 0.0f);
/** Appends another glyph arrangement to this one. */
void addGlyphArrangement (const GlyphArrangement&);


+ 5
- 0
source/modules/juce_graphics/fonts/juce_TextLayout.cpp View File

@@ -635,4 +635,9 @@ void TextLayout::recalculateSize (const AttributedString& text)
width = bounds.getWidth();
height = bounds.getHeight();
}
else
{
width = 0;
height = 0;
}
}

+ 13
- 13
source/modules/juce_graphics/geometry/juce_Line.h View File

@@ -224,8 +224,8 @@ public:
if (length <= 0)
return start;
return Point<ValueType> (start.x + static_cast <ValueType> ((delta.x * distanceFromStart - delta.y * perpendicularDistance) / length),
start.y + static_cast <ValueType> ((delta.y * distanceFromStart + delta.x * perpendicularDistance) / length));
return Point<ValueType> (start.x + static_cast<ValueType> ((delta.x * distanceFromStart - delta.y * perpendicularDistance) / length),
start.y + static_cast<ValueType> ((delta.y * distanceFromStart + delta.x * perpendicularDistance) / length));
}
/** Returns the location of the point which is a given distance along this line
@@ -267,7 +267,7 @@ public:
if (prop >= 0 && prop <= 1.0)
{
pointOnLine = start + delta * static_cast <ValueType> (prop);
pointOnLine = start + delta * static_cast<ValueType> (prop);
return targetPoint.getDistanceFrom (pointOnLine);
}
}
@@ -301,9 +301,9 @@ public:
const double length = delta.x * delta.x + delta.y * delta.y;
return length <= 0 ? 0
: jlimit (ValueType(), static_cast <ValueType> (1),
static_cast <ValueType> ((((point.x - start.x) * delta.x
+ (point.y - start.y) * delta.y) / length)));
: jlimit (ValueType(), static_cast<ValueType> (1),
static_cast<ValueType> ((((point.x - start.x) * delta.x
+ (point.y - start.y) * delta.y) / length)));
}
/** Finds the point on this line which is nearest to a given point.
@@ -375,40 +375,40 @@ private:
{
const ValueType along = (p1.y - p3.y) / d2.y;
intersection = p1.withX (p3.x + along * d2.x);
return along >= 0 && along <= static_cast <ValueType> (1);
return along >= 0 && along <= static_cast<ValueType> (1);
}
else if (d2.y == 0 && d1.y != 0)
{
const ValueType along = (p3.y - p1.y) / d1.y;
intersection = p3.withX (p1.x + along * d1.x);
return along >= 0 && along <= static_cast <ValueType> (1);
return along >= 0 && along <= static_cast<ValueType> (1);
}
else if (d1.x == 0 && d2.x != 0)
{
const ValueType along = (p1.x - p3.x) / d2.x;
intersection = p1.withY (p3.y + along * d2.y);
return along >= 0 && along <= static_cast <ValueType> (1);
return along >= 0 && along <= static_cast<ValueType> (1);
}
else if (d2.x == 0 && d1.x != 0)
{
const ValueType along = (p3.x - p1.x) / d1.x;
intersection = p3.withY (p1.y + along * d1.y);
return along >= 0 && along <= static_cast <ValueType> (1);
return along >= 0 && along <= static_cast<ValueType> (1);
}
}
intersection = (p2 + p3) / static_cast <ValueType> (2);
intersection = (p2 + p3) / static_cast<ValueType> (2);
return false;
}
const ValueType along1 = ((p1.y - p3.y) * d2.x - (p1.x - p3.x) * d2.y) / divisor;
intersection = p1 + d1 * along1;
if (along1 < 0 || along1 > static_cast <ValueType> (1))
if (along1 < 0 || along1 > static_cast<ValueType> (1))
return false;
const ValueType along2 = ((p1.y - p3.y) * d1.x - (p1.x - p3.x) * d1.y) / divisor;
return along2 >= 0 && along2 <= static_cast <ValueType> (1);
return along2 >= 0 && along2 <= static_cast<ValueType> (1);
}
};


+ 5
- 5
source/modules/juce_graphics/geometry/juce_Path.cpp View File

@@ -1567,17 +1567,17 @@ void Path::restoreFromString (StringRef stringVersion)
}
//==============================================================================
Path::Iterator::Iterator (const Path& path_)
: path (path_),
index (0)
Path::Iterator::Iterator (const Path& p) noexcept
: x1 (0), y1 (0), x2 (0), y2 (0), x3 (0), y3 (0),
path (p), index (0)
{
}
Path::Iterator::~Iterator()
Path::Iterator::~Iterator() noexcept
{
}
bool Path::Iterator::next()
bool Path::Iterator::next() noexcept
{
const float* const elements = path.data.elements;


+ 11
- 12
source/modules/juce_graphics/geometry/juce_Path.h View File

@@ -499,21 +499,20 @@ public:
/** Adds a "pie-chart" shape to the path.
The shape is added as a new sub-path. (Any currently open paths will be
left open).
The shape is added as a new sub-path. (Any currently open paths will be left open).
Note that when specifying the start and end angles, the curve will be drawn either clockwise
or anti-clockwise according to whether the end angle is greater than the start. This means
that sometimes you may need to use values greater than 2*Pi for the end angle.
@param area the outer rectangle in which the elliptical outline fits
@param fromRadians the angle (clockwise) in radians at which to start the arc segment (where 0 is the
top-centre of the ellipse)
@param toRadians the angle (clockwise) in radians at which to end the arc segment (where 0 is the
top-centre of the ellipse)
@param segmentBounds the outer rectangle in which the elliptical outline fits
@param fromRadians the angle (clockwise) in radians at which to start the arc segment (where 0 is the
top-centre of the ellipse)
@param toRadians the angle (clockwise) in radians at which to end the arc segment (where 0 is the
top-centre of the ellipse)
@param innerCircleProportionalSize if this is > 0, then the pie will be drawn as a curved band around a hollow
ellipse at its centre, where this value indicates the inner ellipse's size with
respect to the outer one.
ellipse at its centre, where this value indicates the inner ellipse's size with
respect to the outer one.
@see addArc
*/
void addPieSegment (Rectangle<float> segmentBounds,
@@ -718,8 +717,8 @@ public:
{
public:
//==============================================================================
Iterator (const Path& path);
~Iterator();
Iterator (const Path& path) noexcept;
~Iterator() noexcept;
//==============================================================================
/** Moves onto the next element in the path.
@@ -728,7 +727,7 @@ public:
the elementType variable will be set to the type of the current element,
and some of the x and y variables will be filled in with values.
*/
bool next();
bool next() noexcept;
//==============================================================================
enum PathElementType


Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save