From: IOhannes m zmölnig Date: Thu, 6 Feb 2020 08:52:23 +0000 (+0100) Subject: New upstream version 5.4.6~ds0 X-Git-Tag: archive/raspbian/5.4.6_ds0-1+rpi1^2~20^2 X-Git-Url: https://dgit.raspbian.org/?a=commitdiff_plain;h=dd03e7d42c20815564c6eaeeb8220c43b8c18ad7;p=juce.git New upstream version 5.4.6~ds0 --- diff --git a/BREAKING-CHANGES.txt b/BREAKING-CHANGES.txt index 61d162fc..93754f71 100644 --- a/BREAKING-CHANGES.txt +++ b/BREAKING-CHANGES.txt @@ -1,9 +1,105 @@ JUCE breaking changes ===================== +Version 5.4.6 +============= + +Change +------ +AudioProcessorValueTreeState::getRawParameterValue now returns a +std::atomic* instead of a float*. + +Possible Issues +--------------- +Existing code which explicitly mentions the type of the returned value, or +interacts with the dereferenced float in ways unsupported by the std::atomic +wrapper, will fail to compile. Certain evaluation-reordering compiler +optimisations may no longer be possible. + +Workaround +---------- +Update your code to deal with a std::atomic* instead of a float*. + +Rationale +--------- +Returning a std::atomic* allows the JUCE framework to have much stronger +guarantees about thread safety. + + +Change +------ +Removed a workaround from the ASIOAudioIODevice::getOutputLatencyInSamples() +and ASIOAudioIODevice::getInputLatencyInSamples() methods which was adding an +arbitrary amount to the reported latencies to compensate for dodgy, old +drivers. + +Possible Issues +--------------- +Code which relied on these altered values may now behave differently. + +Workaround +---------- +Update your code to deal with the new, correct values reported from the drivers +directly. + +Rationale +--------- +JUCE will now return the latency values as reported by the drivers without +adding anything to them. The workaround was for old drivers and the current +drivers should report the correct values without the need for the workaround. + + +Change +------ +The default behaviour of the AU and AUv3 plug-in wrappers is now to call +get/setStateInformation instead of get/setProgramStateInformation. + +Possible Issues +--------------- +AudioProcessor subclasses which have overridden the default implementations of +get/setProgramStateInformation (which simply call through to +get/setStateInformation) may be unable to load previously saved state; state +previously saved via a call to getProgramStateInformation will be presented to +setStateInformation. + +Workaround +---------- +Enable the JUCE_AU_WRAPPERS_SAVE_PROGRAM_STATES configuration option in the +juce_audio_plugin_client module to preserve backwards compatibility if +required. + +Rationale +--------- +When using overridden get/setProgramStateInformation methods the previous +behaviour of the AU and AUv3 wrappers does not correctly save and restore +state. + + Version 5.4.5 ============= +Change +------ +The alignment of text rendered on macOS using CoreGraphics may have shifted +slightly, depending on the font you have used. The default macOS font has +shifted downwards. + +Possible Issues +--------------- +Meticulously aligned text components of a GUI may now be misaligned. + +Workaround +---------- +Use a custom LookAndFeel to change the location where text is drawn, or use a +different font that matches the previous alignment of your original font. + +Rationale +--------- +This was an unintentional change resulting from moving away from a deprecated +macOS text API. The new alignment is consistent with other rendering engines +(web browsers and text editors) and the software renderer. + + Change ------ The JUCEApplicationBase::backButtonPressed() method now returns a bool to diff --git a/ChangeList.txt b/ChangeList.txt index bf40c1c3..8be14630 100644 --- a/ChangeList.txt +++ b/ChangeList.txt @@ -3,6 +3,15 @@ This file just lists the more notable headline features. For more detailed info about minor changes and bugfixes, please see the git log! +Version 5.4.6 + - Fixed compatibility with macOS versions below 10.11 + - Multiple thread safety improvements + - Added dynamic parameter and parameter group names + - Updated to the latest Android In-App Purchases API + - Improvements to the Windows message queue under high load + - Replaced WaitableEvent internals with std::condition_variable + - Fixed some macOS text alignment issues + Version 5.4.5 - Improved message queue performance on Linux - Added missing lifecycle callbacks on Android Q diff --git a/examples/Assets/DemoUtilities.h b/examples/Assets/DemoUtilities.h index c6438e27..0893cfc0 100644 --- a/examples/Assets/DemoUtilities.h +++ b/examples/Assets/DemoUtilities.h @@ -19,7 +19,7 @@ #pragma once -#include "../JuceLibraryCode/JuceHeader.h" +#include #ifndef PIP_DEMO_UTILITIES_INCLUDED #define PIP_DEMO_UTILITIES_INCLUDED 1 diff --git a/examples/BLOCKS/BlocksDrawingDemo.h b/examples/BLOCKS/BlocksDrawingDemo.h index ed454ebf..d3539397 100644 --- a/examples/BLOCKS/BlocksDrawingDemo.h +++ b/examples/BLOCKS/BlocksDrawingDemo.h @@ -409,7 +409,7 @@ public: setLEDProgram (*activeBlock); } - // Make the on screen Lighpad component visible + // Make the on screen Lightpad component visible lightpadComponent.setVisible (true); infoLabel.setVisible (false); @@ -566,7 +566,7 @@ private: return; } - // If there is no ActiveLED obejct for this LED then create one, + // If there is no ActiveLED object for this LED then create one, // add it to the array, set the LED on the Block and return if (index < 0) { diff --git a/examples/BLOCKS/BlocksMonitorDemo.h b/examples/BLOCKS/BlocksMonitorDemo.h index 3656cccc..c92c0e63 100644 --- a/examples/BLOCKS/BlocksMonitorDemo.h +++ b/examples/BLOCKS/BlocksMonitorDemo.h @@ -95,7 +95,7 @@ public: button->removeListener (this); } - /** Called periodically to update the tooltip with inforamtion about the Block */ + /** Called periodically to update the tooltip with information about the Block */ void updateStatsAndTooltip() { // Get the battery level of this Block and inform any subclasses @@ -972,6 +972,8 @@ private: } //============================================================================== + TooltipWindow tooltipWindow; + PhysicalTopologySource topologySource; OwnedArray blockComponents; BlockComponent* masterBlockComponent = nullptr; diff --git a/examples/DemoRunner/Builds/Android/app/CMakeLists.txt b/examples/DemoRunner/Builds/Android/app/CMakeLists.txt index a6fa1d43..c75d3d7c 100644 --- a/examples/DemoRunner/Builds/Android/app/CMakeLists.txt +++ b/examples/DemoRunner/Builds/Android/app/CMakeLists.txt @@ -8,7 +8,7 @@ SET(BINARY_NAME "juce_jni") add_library("cpufeatures" STATIC "${ANDROID_NDK}/sources/android/cpufeatures/cpu-features.c") set_source_files_properties("${ANDROID_NDK}/sources/android/cpufeatures/cpu-features.c" PROPERTIES COMPILE_FLAGS "-Wno-sign-conversion -Wno-gnu-statement-expression") -add_definitions("-DJUCE_ANDROID=1" "-DJUCE_ANDROID_API_VERSION=23" "-DJUCE_PUSH_NOTIFICATIONS=1" "-DJUCE_PUSH_NOTIFICATIONS_ACTIVITY=\"com/roli/juce/JuceActivity\"" "-DJUCE_ANDROID_GL_ES_VERSION_3_0=1" "-DJUCE_DEMO_RUNNER=1" "-DJUCE_UNIT_TESTS=1" "-DJUCER_ANDROIDSTUDIO_7F0E4A25=1" "-DJUCE_APP_VERSION=5.4.5" "-DJUCE_APP_VERSION_HEX=0x50405") +add_definitions("-DJUCE_ANDROID=1" "-DJUCE_ANDROID_API_VERSION=23" "-DJUCE_PUSH_NOTIFICATIONS=1" "-DJUCE_PUSH_NOTIFICATIONS_ACTIVITY=\"com/roli/juce/JuceActivity\"" "-DJUCE_ANDROID_GL_ES_VERSION_3_0=1" "-DJUCE_DEMO_RUNNER=1" "-DJUCE_UNIT_TESTS=1" "-DJUCER_ANDROIDSTUDIO_7F0E4A25=1" "-DJUCE_APP_VERSION=5.4.6" "-DJUCE_APP_VERSION_HEX=0x50406") include_directories( AFTER "../../../JuceLibraryCode" @@ -729,8 +729,6 @@ add_library( ${BINARY_NAME} "../../../../../modules/juce_core/misc/juce_Result.h" "../../../../../modules/juce_core/misc/juce_RuntimePermissions.cpp" "../../../../../modules/juce_core/misc/juce_RuntimePermissions.h" - "../../../../../modules/juce_core/misc/juce_StdFunctionCompat.cpp" - "../../../../../modules/juce_core/misc/juce_StdFunctionCompat.h" "../../../../../modules/juce_core/misc/juce_Uuid.cpp" "../../../../../modules/juce_core/misc/juce_Uuid.h" "../../../../../modules/juce_core/misc/juce_WindowsRegistry.h" @@ -846,6 +844,7 @@ add_library( ${BINARY_NAME} "../../../../../modules/juce_core/threads/juce_ThreadPool.h" "../../../../../modules/juce_core/threads/juce_TimeSliceThread.cpp" "../../../../../modules/juce_core/threads/juce_TimeSliceThread.h" + "../../../../../modules/juce_core/threads/juce_WaitableEvent.cpp" "../../../../../modules/juce_core/threads/juce_WaitableEvent.h" "../../../../../modules/juce_core/time/juce_PerformanceCounter.cpp" "../../../../../modules/juce_core/time/juce_PerformanceCounter.h" @@ -2334,8 +2333,6 @@ set_source_files_properties("../../../../../modules/juce_core/misc/juce_Result.c set_source_files_properties("../../../../../modules/juce_core/misc/juce_Result.h" PROPERTIES HEADER_FILE_ONLY TRUE) set_source_files_properties("../../../../../modules/juce_core/misc/juce_RuntimePermissions.cpp" PROPERTIES HEADER_FILE_ONLY TRUE) set_source_files_properties("../../../../../modules/juce_core/misc/juce_RuntimePermissions.h" PROPERTIES HEADER_FILE_ONLY TRUE) -set_source_files_properties("../../../../../modules/juce_core/misc/juce_StdFunctionCompat.cpp" PROPERTIES HEADER_FILE_ONLY TRUE) -set_source_files_properties("../../../../../modules/juce_core/misc/juce_StdFunctionCompat.h" PROPERTIES HEADER_FILE_ONLY TRUE) set_source_files_properties("../../../../../modules/juce_core/misc/juce_Uuid.cpp" PROPERTIES HEADER_FILE_ONLY TRUE) set_source_files_properties("../../../../../modules/juce_core/misc/juce_Uuid.h" PROPERTIES HEADER_FILE_ONLY TRUE) set_source_files_properties("../../../../../modules/juce_core/misc/juce_WindowsRegistry.h" PROPERTIES HEADER_FILE_ONLY TRUE) @@ -2451,6 +2448,7 @@ set_source_files_properties("../../../../../modules/juce_core/threads/juce_Threa set_source_files_properties("../../../../../modules/juce_core/threads/juce_ThreadPool.h" PROPERTIES HEADER_FILE_ONLY TRUE) set_source_files_properties("../../../../../modules/juce_core/threads/juce_TimeSliceThread.cpp" PROPERTIES HEADER_FILE_ONLY TRUE) set_source_files_properties("../../../../../modules/juce_core/threads/juce_TimeSliceThread.h" PROPERTIES HEADER_FILE_ONLY TRUE) +set_source_files_properties("../../../../../modules/juce_core/threads/juce_WaitableEvent.cpp" PROPERTIES HEADER_FILE_ONLY TRUE) set_source_files_properties("../../../../../modules/juce_core/threads/juce_WaitableEvent.h" PROPERTIES HEADER_FILE_ONLY TRUE) set_source_files_properties("../../../../../modules/juce_core/time/juce_PerformanceCounter.cpp" PROPERTIES HEADER_FILE_ONLY TRUE) set_source_files_properties("../../../../../modules/juce_core/time/juce_PerformanceCounter.h" PROPERTIES HEADER_FILE_ONLY TRUE) diff --git a/examples/DemoRunner/Builds/Android/app/src/main/AndroidManifest.xml b/examples/DemoRunner/Builds/Android/app/src/main/AndroidManifest.xml index 80922f54..f577cd8c 100644 --- a/examples/DemoRunner/Builds/Android/app/src/main/AndroidManifest.xml +++ b/examples/DemoRunner/Builds/Android/app/src/main/AndroidManifest.xml @@ -1,6 +1,6 @@ - @@ -10,6 +10,7 @@ + diff --git a/examples/DemoRunner/Builds/Android/app/src/main/assets/DemoUtilities.h b/examples/DemoRunner/Builds/Android/app/src/main/assets/DemoUtilities.h index c6438e27..0893cfc0 100644 --- a/examples/DemoRunner/Builds/Android/app/src/main/assets/DemoUtilities.h +++ b/examples/DemoRunner/Builds/Android/app/src/main/assets/DemoUtilities.h @@ -19,7 +19,7 @@ #pragma once -#include "../JuceLibraryCode/JuceHeader.h" +#include #ifndef PIP_DEMO_UTILITIES_INCLUDED #define PIP_DEMO_UTILITIES_INCLUDED 1 diff --git a/examples/DemoRunner/Builds/Android/build.gradle b/examples/DemoRunner/Builds/Android/build.gradle index 2df9a8e7..cfd3a2f8 100644 --- a/examples/DemoRunner/Builds/Android/build.gradle +++ b/examples/DemoRunner/Builds/Android/build.gradle @@ -4,7 +4,7 @@ buildscript { jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:3.2.1' + classpath 'com.android.tools.build:gradle:3.5.3' } } diff --git a/examples/DemoRunner/Builds/Android/gradle/wrapper/gradle-wrapper.properties b/examples/DemoRunner/Builds/Android/gradle/wrapper/gradle-wrapper.properties index b460908d..b66802c7 100644 --- a/examples/DemoRunner/Builds/Android/gradle/wrapper/gradle-wrapper.properties +++ b/examples/DemoRunner/Builds/Android/gradle/wrapper/gradle-wrapper.properties @@ -1 +1 @@ -distributionUrl=https\://services.gradle.org/distributions/gradle-4.10-all.zip \ No newline at end of file +distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip \ No newline at end of file diff --git a/examples/DemoRunner/Builds/LinuxMakefile/Makefile b/examples/DemoRunner/Builds/LinuxMakefile/Makefile index a63eabe4..56acdc6f 100644 --- a/examples/DemoRunner/Builds/LinuxMakefile/Makefile +++ b/examples/DemoRunner/Builds/LinuxMakefile/Makefile @@ -35,7 +35,7 @@ ifeq ($(CONFIG),Debug) TARGET_ARCH := -march=native endif - JUCE_CPPFLAGS := $(DEPFLAGS) -DLINUX=1 -DDEBUG=1 -D_DEBUG=1 -DJUCE_DEMO_RUNNER=1 -DJUCE_UNIT_TESTS=1 -DJUCER_LINUX_MAKE_6D53C8B4=1 -DJUCE_APP_VERSION=5.4.5 -DJUCE_APP_VERSION_HEX=0x50405 $(shell pkg-config --cflags alsa x11 xinerama xext freetype2 webkit2gtk-4.0 gtk+-x11-3.0 libcurl) -pthread -I../../JuceLibraryCode -I../../../../modules $(CPPFLAGS) + JUCE_CPPFLAGS := $(DEPFLAGS) -DLINUX=1 -DDEBUG=1 -D_DEBUG=1 -DJUCE_DEMO_RUNNER=1 -DJUCE_UNIT_TESTS=1 -DJUCER_LINUX_MAKE_6D53C8B4=1 -DJUCE_APP_VERSION=5.4.6 -DJUCE_APP_VERSION_HEX=0x50406 $(shell pkg-config --cflags alsa x11 xinerama xext freetype2 webkit2gtk-4.0 gtk+-x11-3.0 libcurl) -pthread -I../../JuceLibraryCode -I../../../../modules $(CPPFLAGS) JUCE_CPPFLAGS_APP := -DJucePlugin_Build_VST=0 -DJucePlugin_Build_VST3=0 -DJucePlugin_Build_AU=0 -DJucePlugin_Build_AUv3=0 -DJucePlugin_Build_RTAS=0 -DJucePlugin_Build_AAX=0 -DJucePlugin_Build_Standalone=0 -DJucePlugin_Build_Unity=0 JUCE_TARGET_APP := DemoRunner @@ -56,7 +56,7 @@ ifeq ($(CONFIG),Release) TARGET_ARCH := -march=native endif - JUCE_CPPFLAGS := $(DEPFLAGS) -DLINUX=1 -DNDEBUG=1 -DJUCE_DEMO_RUNNER=1 -DJUCE_UNIT_TESTS=1 -DJUCER_LINUX_MAKE_6D53C8B4=1 -DJUCE_APP_VERSION=5.4.5 -DJUCE_APP_VERSION_HEX=0x50405 $(shell pkg-config --cflags alsa x11 xinerama xext freetype2 webkit2gtk-4.0 gtk+-x11-3.0 libcurl) -pthread -I../../JuceLibraryCode -I../../../../modules $(CPPFLAGS) + JUCE_CPPFLAGS := $(DEPFLAGS) -DLINUX=1 -DNDEBUG=1 -DJUCE_DEMO_RUNNER=1 -DJUCE_UNIT_TESTS=1 -DJUCER_LINUX_MAKE_6D53C8B4=1 -DJUCE_APP_VERSION=5.4.6 -DJUCE_APP_VERSION_HEX=0x50406 $(shell pkg-config --cflags alsa x11 xinerama xext freetype2 webkit2gtk-4.0 gtk+-x11-3.0 libcurl) -pthread -I../../JuceLibraryCode -I../../../../modules $(CPPFLAGS) JUCE_CPPFLAGS_APP := -DJucePlugin_Build_VST=0 -DJucePlugin_Build_VST3=0 -DJucePlugin_Build_AU=0 -DJucePlugin_Build_AUv3=0 -DJucePlugin_Build_RTAS=0 -DJucePlugin_Build_AAX=0 -DJucePlugin_Build_Standalone=0 -DJucePlugin_Build_Unity=0 JUCE_TARGET_APP := DemoRunner diff --git a/examples/DemoRunner/Builds/MacOSX/App.entitlements b/examples/DemoRunner/Builds/MacOSX/App.entitlements new file mode 100644 index 00000000..6631ffa6 --- /dev/null +++ b/examples/DemoRunner/Builds/MacOSX/App.entitlements @@ -0,0 +1,6 @@ + + + + + + diff --git a/examples/DemoRunner/Builds/MacOSX/DemoRunner.entitlements b/examples/DemoRunner/Builds/MacOSX/DemoRunner.entitlements deleted file mode 100644 index 6631ffa6..00000000 --- a/examples/DemoRunner/Builds/MacOSX/DemoRunner.entitlements +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/examples/DemoRunner/Builds/MacOSX/DemoRunner.xcodeproj/project.pbxproj b/examples/DemoRunner/Builds/MacOSX/DemoRunner.xcodeproj/project.pbxproj index 0aee90e6..2b5ef855 100644 --- a/examples/DemoRunner/Builds/MacOSX/DemoRunner.xcodeproj/project.pbxproj +++ b/examples/DemoRunner/Builds/MacOSX/DemoRunner.xcodeproj/project.pbxproj @@ -69,6 +69,10 @@ isa = PBXBuildFile; fileRef = 96D99A08027CA35D6A4E5CFD; }; + 47ED2C78B05B8A6A00E36C46 = { + isa = PBXBuildFile; + fileRef = 685A261BE78585293F3EAD36; + }; D3D8CDCE42E8BE31C7247E38 = { isa = PBXBuildFile; fileRef = 0ECB4FCD24794CE516792552; @@ -243,13 +247,6 @@ path = "../../../../modules/juce_audio_utils"; sourceTree = "SOURCE_ROOT"; }; - 0CCFDC1D1C7B8A12BF4822F1 = { - isa = PBXFileReference; - lastKnownFileType = text.plist.xml; - name = DemoRunner.entitlements; - path = DemoRunner.entitlements; - sourceTree = "SOURCE_ROOT"; - }; 0ECB4FCD24794CE516792552 = { isa = PBXFileReference; lastKnownFileType = folder; @@ -467,6 +464,13 @@ path = "../../../../modules/juce_audio_basics"; sourceTree = "SOURCE_ROOT"; }; + 685A261BE78585293F3EAD36 = { + isa = PBXFileReference; + lastKnownFileType = folder; + name = Assets; + path = ../../../Assets; + sourceTree = ""; + }; 6C198AF93E1F6E682189E2F6 = { isa = PBXFileReference; lastKnownFileType = file; @@ -856,6 +860,7 @@ D87DCD5DA4EC8D78DFF37FCC = { isa = PBXGroup; children = ( + 685A261BE78585293F3EAD36, 0ECB4FCD24794CE516792552, 388A8209DBB1B08594266121, 5CD17151385A69F1E07FE85B, @@ -929,8 +934,8 @@ "JUCE_DEMO_RUNNER=1", "JUCE_UNIT_TESTS=1", "JUCER_XCODE_MAC_F6D2F4CF=1", - "JUCE_APP_VERSION=5.4.5", - "JUCE_APP_VERSION_HEX=0x50405", + "JUCE_APP_VERSION=5.4.6", + "JUCE_APP_VERSION_HEX=0x50406", "JucePlugin_Build_VST=0", "JucePlugin_Build_VST3=0", "JucePlugin_Build_AU=0", @@ -975,8 +980,8 @@ "JUCE_DEMO_RUNNER=1", "JUCE_UNIT_TESTS=1", "JUCER_XCODE_MAC_F6D2F4CF=1", - "JUCE_APP_VERSION=5.4.5", - "JUCE_APP_VERSION_HEX=0x50405", + "JUCE_APP_VERSION=5.4.6", + "JUCE_APP_VERSION_HEX=0x50406", "JucePlugin_Build_VST=0", "JucePlugin_Build_VST3=0", "JucePlugin_Build_AU=0", @@ -1047,6 +1052,7 @@ GCC_WARN_UNUSED_VARIABLE = YES; ONLY_ACTIVE_ARCH = YES; PRODUCT_NAME = "DemoRunner"; + SDKROOT = macosx; WARNING_CFLAGS = "-Wreorder"; ZERO_LINK = NO; }; @@ -1092,6 +1098,7 @@ GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; PRODUCT_NAME = "DemoRunner"; + SDKROOT = macosx; WARNING_CFLAGS = "-Wreorder"; ZERO_LINK = NO; }; @@ -1123,6 +1130,7 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + 47ED2C78B05B8A6A00E36C46, D3D8CDCE42E8BE31C7247E38, 3B3952A9A14320312EF890A5, 41BAB55E0D992708EF06E2C4, diff --git a/examples/DemoRunner/Builds/MacOSX/Info-App.plist b/examples/DemoRunner/Builds/MacOSX/Info-App.plist index 9aee797c..2c5d4b38 100644 --- a/examples/DemoRunner/Builds/MacOSX/Info-App.plist +++ b/examples/DemoRunner/Builds/MacOSX/Info-App.plist @@ -22,9 +22,9 @@ CFBundleSignature ???? CFBundleShortVersionString - 5.4.5 + 5.4.6 CFBundleVersion - 5.4.5 + 5.4.6 NSHumanReadableCopyright Copyright (c) 2018 - ROLI Ltd. NSHighResolutionCapable diff --git a/examples/DemoRunner/Builds/VisualStudio2015/DemoRunner_App.vcxproj b/examples/DemoRunner/Builds/VisualStudio2015/DemoRunner_App.vcxproj index 05447de1..b0db8d97 100644 --- a/examples/DemoRunner/Builds/VisualStudio2015/DemoRunner_App.vcxproj +++ b/examples/DemoRunner/Builds/VisualStudio2015/DemoRunner_App.vcxproj @@ -64,7 +64,7 @@ Disabled ProgramDatabase ..\..\JuceLibraryCode;..\..\..\..\modules;%(AdditionalIncludeDirectories) - _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;DEBUG;_DEBUG;JUCE_DEMO_RUNNER=1;JUCE_UNIT_TESTS=1;JUCER_VS2015_78A5022=1;JUCE_APP_VERSION=5.4.5;JUCE_APP_VERSION_HEX=0x50405;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_RTAS=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;DEBUG;_DEBUG;JUCE_DEMO_RUNNER=1;JUCE_UNIT_TESTS=1;JUCER_VS2015_78A5022=1;JUCE_APP_VERSION=5.4.6;JUCE_APP_VERSION_HEX=0x50406;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_RTAS=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;%(PreprocessorDefinitions) MultiThreadedDebugDLL true @@ -106,7 +106,7 @@ Full ..\..\JuceLibraryCode;..\..\..\..\modules;%(AdditionalIncludeDirectories) - _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;JUCE_DEMO_RUNNER=1;JUCE_UNIT_TESTS=1;JUCER_VS2015_78A5022=1;JUCE_APP_VERSION=5.4.5;JUCE_APP_VERSION_HEX=0x50405;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_RTAS=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;JUCE_DEMO_RUNNER=1;JUCE_UNIT_TESTS=1;JUCER_VS2015_78A5022=1;JUCE_APP_VERSION=5.4.6;JUCE_APP_VERSION_HEX=0x50406;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_RTAS=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;%(PreprocessorDefinitions) MultiThreaded true @@ -965,9 +965,6 @@ true - - true - true @@ -1118,6 +1115,9 @@ true + + true + true @@ -2641,7 +2641,6 @@ - diff --git a/examples/DemoRunner/Builds/VisualStudio2015/DemoRunner_App.vcxproj.filters b/examples/DemoRunner/Builds/VisualStudio2015/DemoRunner_App.vcxproj.filters index d669b590..8bdd409c 100644 --- a/examples/DemoRunner/Builds/VisualStudio2015/DemoRunner_App.vcxproj.filters +++ b/examples/DemoRunner/Builds/VisualStudio2015/DemoRunner_App.vcxproj.filters @@ -1396,9 +1396,6 @@ JUCE Modules\juce_core\misc - - JUCE Modules\juce_core\misc - JUCE Modules\juce_core\misc @@ -1564,6 +1561,9 @@ JUCE Modules\juce_core\threads + + JUCE Modules\juce_core\threads + JUCE Modules\juce_core\time @@ -3996,9 +3996,6 @@ JUCE Modules\juce_core\misc - - JUCE Modules\juce_core\misc - JUCE Modules\juce_core\misc diff --git a/examples/DemoRunner/Builds/VisualStudio2015/resources.rc b/examples/DemoRunner/Builds/VisualStudio2015/resources.rc index b9e17aa7..ea054be6 100644 --- a/examples/DemoRunner/Builds/VisualStudio2015/resources.rc +++ b/examples/DemoRunner/Builds/VisualStudio2015/resources.rc @@ -7,7 +7,7 @@ #include VS_VERSION_INFO VERSIONINFO -FILEVERSION 5,4,5,0 +FILEVERSION 5,4,6,0 BEGIN BLOCK "StringFileInfo" BEGIN @@ -16,9 +16,9 @@ BEGIN VALUE "CompanyName", "ROLI Ltd.\0" VALUE "LegalCopyright", "Copyright (c) 2018 - ROLI Ltd.\0" VALUE "FileDescription", "DemoRunner\0" - VALUE "FileVersion", "5.4.5\0" + VALUE "FileVersion", "5.4.6\0" VALUE "ProductName", "DemoRunner\0" - VALUE "ProductVersion", "5.4.5\0" + VALUE "ProductVersion", "5.4.6\0" END END diff --git a/examples/DemoRunner/Builds/VisualStudio2017/DemoRunner_App.vcxproj b/examples/DemoRunner/Builds/VisualStudio2017/DemoRunner_App.vcxproj index cd93c15b..0f6f601f 100644 --- a/examples/DemoRunner/Builds/VisualStudio2017/DemoRunner_App.vcxproj +++ b/examples/DemoRunner/Builds/VisualStudio2017/DemoRunner_App.vcxproj @@ -64,7 +64,7 @@ Disabled ProgramDatabase ..\..\JuceLibraryCode;..\..\..\..\modules;%(AdditionalIncludeDirectories) - _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;DEBUG;_DEBUG;JUCE_DEMO_RUNNER=1;JUCE_UNIT_TESTS=1;JUCER_VS2017_78A5024=1;JUCE_APP_VERSION=5.4.5;JUCE_APP_VERSION_HEX=0x50405;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_RTAS=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;DEBUG;_DEBUG;JUCE_DEMO_RUNNER=1;JUCE_UNIT_TESTS=1;JUCER_VS2017_78A5024=1;JUCE_APP_VERSION=5.4.6;JUCE_APP_VERSION_HEX=0x50406;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_RTAS=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;%(PreprocessorDefinitions) MultiThreadedDebugDLL true @@ -106,7 +106,7 @@ Full ..\..\JuceLibraryCode;..\..\..\..\modules;%(AdditionalIncludeDirectories) - _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;JUCE_DEMO_RUNNER=1;JUCE_UNIT_TESTS=1;JUCER_VS2017_78A5024=1;JUCE_APP_VERSION=5.4.5;JUCE_APP_VERSION_HEX=0x50405;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_RTAS=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;JUCE_DEMO_RUNNER=1;JUCE_UNIT_TESTS=1;JUCER_VS2017_78A5024=1;JUCE_APP_VERSION=5.4.6;JUCE_APP_VERSION_HEX=0x50406;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_RTAS=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;%(PreprocessorDefinitions) MultiThreaded true @@ -965,9 +965,6 @@ true - - true - true @@ -1118,6 +1115,9 @@ true + + true + true @@ -2641,7 +2641,6 @@ - diff --git a/examples/DemoRunner/Builds/VisualStudio2017/DemoRunner_App.vcxproj.filters b/examples/DemoRunner/Builds/VisualStudio2017/DemoRunner_App.vcxproj.filters index 1c01ce48..4b163b6d 100644 --- a/examples/DemoRunner/Builds/VisualStudio2017/DemoRunner_App.vcxproj.filters +++ b/examples/DemoRunner/Builds/VisualStudio2017/DemoRunner_App.vcxproj.filters @@ -1396,9 +1396,6 @@ JUCE Modules\juce_core\misc - - JUCE Modules\juce_core\misc - JUCE Modules\juce_core\misc @@ -1564,6 +1561,9 @@ JUCE Modules\juce_core\threads + + JUCE Modules\juce_core\threads + JUCE Modules\juce_core\time @@ -3996,9 +3996,6 @@ JUCE Modules\juce_core\misc - - JUCE Modules\juce_core\misc - JUCE Modules\juce_core\misc diff --git a/examples/DemoRunner/Builds/VisualStudio2017/resources.rc b/examples/DemoRunner/Builds/VisualStudio2017/resources.rc index b9e17aa7..ea054be6 100644 --- a/examples/DemoRunner/Builds/VisualStudio2017/resources.rc +++ b/examples/DemoRunner/Builds/VisualStudio2017/resources.rc @@ -7,7 +7,7 @@ #include VS_VERSION_INFO VERSIONINFO -FILEVERSION 5,4,5,0 +FILEVERSION 5,4,6,0 BEGIN BLOCK "StringFileInfo" BEGIN @@ -16,9 +16,9 @@ BEGIN VALUE "CompanyName", "ROLI Ltd.\0" VALUE "LegalCopyright", "Copyright (c) 2018 - ROLI Ltd.\0" VALUE "FileDescription", "DemoRunner\0" - VALUE "FileVersion", "5.4.5\0" + VALUE "FileVersion", "5.4.6\0" VALUE "ProductName", "DemoRunner\0" - VALUE "ProductVersion", "5.4.5\0" + VALUE "ProductVersion", "5.4.6\0" END END diff --git a/examples/DemoRunner/Builds/VisualStudio2019/DemoRunner_App.vcxproj b/examples/DemoRunner/Builds/VisualStudio2019/DemoRunner_App.vcxproj index 8ce8e592..779d691d 100644 --- a/examples/DemoRunner/Builds/VisualStudio2019/DemoRunner_App.vcxproj +++ b/examples/DemoRunner/Builds/VisualStudio2019/DemoRunner_App.vcxproj @@ -64,7 +64,7 @@ Disabled ProgramDatabase ..\..\JuceLibraryCode;..\..\..\..\modules;%(AdditionalIncludeDirectories) - _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;DEBUG;_DEBUG;JUCE_DEMO_RUNNER=1;JUCE_UNIT_TESTS=1;JUCER_VS2019_78A5026=1;JUCE_APP_VERSION=5.4.5;JUCE_APP_VERSION_HEX=0x50405;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_RTAS=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;DEBUG;_DEBUG;JUCE_DEMO_RUNNER=1;JUCE_UNIT_TESTS=1;JUCER_VS2019_78A5026=1;JUCE_APP_VERSION=5.4.6;JUCE_APP_VERSION_HEX=0x50406;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_RTAS=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;%(PreprocessorDefinitions) MultiThreadedDebugDLL true @@ -106,7 +106,7 @@ Full ..\..\JuceLibraryCode;..\..\..\..\modules;%(AdditionalIncludeDirectories) - _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;JUCE_DEMO_RUNNER=1;JUCE_UNIT_TESTS=1;JUCER_VS2019_78A5026=1;JUCE_APP_VERSION=5.4.5;JUCE_APP_VERSION_HEX=0x50405;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_RTAS=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;JUCE_DEMO_RUNNER=1;JUCE_UNIT_TESTS=1;JUCER_VS2019_78A5026=1;JUCE_APP_VERSION=5.4.6;JUCE_APP_VERSION_HEX=0x50406;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_RTAS=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;%(PreprocessorDefinitions) MultiThreaded true @@ -965,9 +965,6 @@ true - - true - true @@ -1118,6 +1115,9 @@ true + + true + true @@ -2641,7 +2641,6 @@ - diff --git a/examples/DemoRunner/Builds/VisualStudio2019/DemoRunner_App.vcxproj.filters b/examples/DemoRunner/Builds/VisualStudio2019/DemoRunner_App.vcxproj.filters index 71680ce4..334070cb 100644 --- a/examples/DemoRunner/Builds/VisualStudio2019/DemoRunner_App.vcxproj.filters +++ b/examples/DemoRunner/Builds/VisualStudio2019/DemoRunner_App.vcxproj.filters @@ -1396,9 +1396,6 @@ JUCE Modules\juce_core\misc - - JUCE Modules\juce_core\misc - JUCE Modules\juce_core\misc @@ -1564,6 +1561,9 @@ JUCE Modules\juce_core\threads + + JUCE Modules\juce_core\threads + JUCE Modules\juce_core\time @@ -3996,9 +3996,6 @@ JUCE Modules\juce_core\misc - - JUCE Modules\juce_core\misc - JUCE Modules\juce_core\misc diff --git a/examples/DemoRunner/Builds/VisualStudio2019/resources.rc b/examples/DemoRunner/Builds/VisualStudio2019/resources.rc index b9e17aa7..ea054be6 100644 --- a/examples/DemoRunner/Builds/VisualStudio2019/resources.rc +++ b/examples/DemoRunner/Builds/VisualStudio2019/resources.rc @@ -7,7 +7,7 @@ #include VS_VERSION_INFO VERSIONINFO -FILEVERSION 5,4,5,0 +FILEVERSION 5,4,6,0 BEGIN BLOCK "StringFileInfo" BEGIN @@ -16,9 +16,9 @@ BEGIN VALUE "CompanyName", "ROLI Ltd.\0" VALUE "LegalCopyright", "Copyright (c) 2018 - ROLI Ltd.\0" VALUE "FileDescription", "DemoRunner\0" - VALUE "FileVersion", "5.4.5\0" + VALUE "FileVersion", "5.4.6\0" VALUE "ProductName", "DemoRunner\0" - VALUE "ProductVersion", "5.4.5\0" + VALUE "ProductVersion", "5.4.6\0" END END diff --git a/examples/DemoRunner/Builds/iOS/App.entitlements b/examples/DemoRunner/Builds/iOS/App.entitlements new file mode 100644 index 00000000..42bc7ba9 --- /dev/null +++ b/examples/DemoRunner/Builds/iOS/App.entitlements @@ -0,0 +1,18 @@ + + + + + com.apple.developer.icloud-container-identifiers + + iCloud.$(CFBundleIdentifier) + + com.apple.developer.icloud-services + + CloudDocuments + + com.apple.developer.ubiquity-container-identifiers + + iCloud.$(CFBundleIdentifier) + + + diff --git a/examples/DemoRunner/Builds/iOS/DemoRunner.entitlements b/examples/DemoRunner/Builds/iOS/DemoRunner.entitlements deleted file mode 100644 index 42bc7ba9..00000000 --- a/examples/DemoRunner/Builds/iOS/DemoRunner.entitlements +++ /dev/null @@ -1,18 +0,0 @@ - - - - - com.apple.developer.icloud-container-identifiers - - iCloud.$(CFBundleIdentifier) - - com.apple.developer.icloud-services - - CloudDocuments - - com.apple.developer.ubiquity-container-identifiers - - iCloud.$(CFBundleIdentifier) - - - diff --git a/examples/DemoRunner/Builds/iOS/DemoRunner.xcodeproj/project.pbxproj b/examples/DemoRunner/Builds/iOS/DemoRunner.xcodeproj/project.pbxproj index 5751f074..49d4408e 100644 --- a/examples/DemoRunner/Builds/iOS/DemoRunner.xcodeproj/project.pbxproj +++ b/examples/DemoRunner/Builds/iOS/DemoRunner.xcodeproj/project.pbxproj @@ -232,13 +232,6 @@ path = "../../../../modules/juce_audio_utils"; sourceTree = "SOURCE_ROOT"; }; - 0CCFDC1D1C7B8A12BF4822F1 = { - isa = PBXFileReference; - lastKnownFileType = text.plist.xml; - name = DemoRunner.entitlements; - path = DemoRunner.entitlements; - sourceTree = "SOURCE_ROOT"; - }; 112FFCB73597157E721BCDF2 = { isa = PBXFileReference; lastKnownFileType = file; @@ -295,6 +288,13 @@ path = ../../Source/Main.cpp; sourceTree = "SOURCE_ROOT"; }; + 2CDA0CB288452DA016E874BC = { + isa = PBXFileReference; + lastKnownFileType = text.plist.xml; + name = App.entitlements; + path = App.entitlements; + sourceTree = "SOURCE_ROOT"; + }; 346450C70C964FD9640B6086 = { isa = PBXFileReference; lastKnownFileType = file; @@ -907,7 +907,7 @@ CLANG_CXX_LANGUAGE_STANDARD = "c++14"; CLANG_CXX_LIBRARY = "libc++"; CLANG_LINK_OBJC_RUNTIME = NO; - CODE_SIGN_ENTITLEMENTS = "DemoRunner.entitlements"; + CODE_SIGN_ENTITLEMENTS = "App.entitlements"; COMBINE_HIDPI_IMAGES = YES; CONFIGURATION_BUILD_DIR = "$(PROJECT_DIR)/build/$(CONFIGURATION)"; COPY_PHASE_STRIP = NO; @@ -919,8 +919,8 @@ "JUCE_DEMO_RUNNER=1", "JUCE_UNIT_TESTS=1", "JUCER_XCODE_IPHONE_5BC26AE3=1", - "JUCE_APP_VERSION=5.4.5", - "JUCE_APP_VERSION_HEX=0x50405", + "JUCE_APP_VERSION=5.4.6", + "JUCE_APP_VERSION_HEX=0x50406", "JucePlugin_Build_VST=0", "JucePlugin_Build_VST3=0", "JucePlugin_Build_AU=0", @@ -954,7 +954,7 @@ CLANG_CXX_LANGUAGE_STANDARD = "c++14"; CLANG_CXX_LIBRARY = "libc++"; CLANG_LINK_OBJC_RUNTIME = NO; - CODE_SIGN_ENTITLEMENTS = "DemoRunner.entitlements"; + CODE_SIGN_ENTITLEMENTS = "App.entitlements"; COMBINE_HIDPI_IMAGES = YES; CONFIGURATION_BUILD_DIR = "$(PROJECT_DIR)/build/$(CONFIGURATION)"; DEAD_CODE_STRIPPING = YES; @@ -966,8 +966,8 @@ "JUCE_DEMO_RUNNER=1", "JUCE_UNIT_TESTS=1", "JUCER_XCODE_IPHONE_5BC26AE3=1", - "JUCE_APP_VERSION=5.4.5", - "JUCE_APP_VERSION_HEX=0x50405", + "JUCE_APP_VERSION=5.4.6", + "JUCE_APP_VERSION_HEX=0x50406", "JucePlugin_Build_VST=0", "JucePlugin_Build_VST3=0", "JucePlugin_Build_AU=0", diff --git a/examples/DemoRunner/Builds/iOS/Info-App.plist b/examples/DemoRunner/Builds/iOS/Info-App.plist index 39de13f0..1b8b1b70 100644 --- a/examples/DemoRunner/Builds/iOS/Info-App.plist +++ b/examples/DemoRunner/Builds/iOS/Info-App.plist @@ -30,9 +30,9 @@ CFBundleSignature ???? CFBundleShortVersionString - 5.4.5 + 5.4.6 CFBundleVersion - 5.4.5 + 5.4.6 NSHumanReadableCopyright Copyright (c) 2018 - ROLI Ltd. NSHighResolutionCapable diff --git a/examples/DemoRunner/DemoRunner.jucer b/examples/DemoRunner/DemoRunner.jucer index 4a28f30c..56059d32 100644 --- a/examples/DemoRunner/DemoRunner.jucer +++ b/examples/DemoRunner/DemoRunner.jucer @@ -1,7 +1,7 @@ - @@ -30,7 +30,7 @@ diff --git a/examples/DemoRunner/JuceLibraryCode/AppConfig.h b/examples/DemoRunner/JuceLibraryCode/AppConfig.h index fd7cbb98..048b13f1 100644 --- a/examples/DemoRunner/JuceLibraryCode/AppConfig.h +++ b/examples/DemoRunner/JuceLibraryCode/AppConfig.h @@ -47,7 +47,7 @@ #define JUCE_USE_DARK_SPLASH_SCREEN 1 -#define JUCE_PROJUCER_VERSION 0x50405 +#define JUCE_PROJUCER_VERSION 0x50406 //============================================================================== #define JUCE_MODULE_AVAILABLE_juce_analytics 1 @@ -242,8 +242,8 @@ //============================================================================== // juce_events flags: -#ifndef JUCE_EXECUTE_APP_SUSPEND_ON_IOS_BACKGROUND_TASK - //#define JUCE_EXECUTE_APP_SUSPEND_ON_IOS_BACKGROUND_TASK 0 +#ifndef JUCE_EXECUTE_APP_SUSPEND_ON_BACKGROUND_TASK + //#define JUCE_EXECUTE_APP_SUSPEND_ON_BACKGROUND_TASK 0 #endif //============================================================================== diff --git a/examples/DemoRunner/JuceLibraryCode/JuceHeader.h b/examples/DemoRunner/JuceLibraryCode/JuceHeader.h index c1d016dd..0d632903 100644 --- a/examples/DemoRunner/JuceLibraryCode/JuceHeader.h +++ b/examples/DemoRunner/JuceLibraryCode/JuceHeader.h @@ -56,7 +56,7 @@ namespace ProjectInfo { const char* const projectName = "DemoRunner"; const char* const companyName = "ROLI Ltd."; - const char* const versionString = "5.4.5"; - const int versionNumber = 0x50405; + const char* const versionString = "5.4.6"; + const int versionNumber = 0x50406; } #endif diff --git a/examples/DemoRunner/Source/Demos/DemoPIPs1.cpp b/examples/DemoRunner/Source/Demos/DemoPIPs1.cpp index 9fe417f9..f030078e 100644 --- a/examples/DemoRunner/Source/Demos/DemoPIPs1.cpp +++ b/examples/DemoRunner/Source/Demos/DemoPIPs1.cpp @@ -24,7 +24,7 @@ ============================================================================== */ -#include "../JuceLibraryCode/JuceHeader.h" +#include #include "../../../Assets/DemoUtilities.h" #include "JUCEDemos.h" diff --git a/examples/DemoRunner/Source/Demos/DemoPIPs2.cpp b/examples/DemoRunner/Source/Demos/DemoPIPs2.cpp index b7d95de8..d2584529 100644 --- a/examples/DemoRunner/Source/Demos/DemoPIPs2.cpp +++ b/examples/DemoRunner/Source/Demos/DemoPIPs2.cpp @@ -24,7 +24,7 @@ ============================================================================== */ -#include "../JuceLibraryCode/JuceHeader.h" +#include #include "../../../Assets/DemoUtilities.h" #include "JUCEDemos.h" diff --git a/examples/DemoRunner/Source/Demos/JUCEDemos.cpp b/examples/DemoRunner/Source/Demos/JUCEDemos.cpp index e6092216..9c7f5132 100644 --- a/examples/DemoRunner/Source/Demos/JUCEDemos.cpp +++ b/examples/DemoRunner/Source/Demos/JUCEDemos.cpp @@ -24,7 +24,7 @@ ============================================================================== */ -#include "../JuceLibraryCode/JuceHeader.h" +#include #include "../../../Assets/DemoUtilities.h" #include "JUCEDemos.h" diff --git a/examples/DemoRunner/Source/Main.cpp b/examples/DemoRunner/Source/Main.cpp index edbd8f8e..537d8307 100644 --- a/examples/DemoRunner/Source/Main.cpp +++ b/examples/DemoRunner/Source/Main.cpp @@ -24,7 +24,7 @@ ============================================================================== */ -#include "../JuceLibraryCode/JuceHeader.h" +#include #include "../../Assets/DemoUtilities.h" #include "UI/MainComponent.h" diff --git a/examples/DemoRunner/Source/UI/DemoContentComponent.cpp b/examples/DemoRunner/Source/UI/DemoContentComponent.cpp index 1c6d9a35..c00b8165 100644 --- a/examples/DemoRunner/Source/UI/DemoContentComponent.cpp +++ b/examples/DemoRunner/Source/UI/DemoContentComponent.cpp @@ -103,7 +103,7 @@ struct CodeContent : public Component //============================================================================== DemoContentComponent::DemoContentComponent (Component& mainComponent, std::function callback) : TabbedComponent (TabbedButtonBar::Orientation::TabsAtTop), - demoChangedCallback (callback) + demoChangedCallback (std::move (callback)) { demoContent.reset (new DemoContent()); addTab ("Demo", Colours::transparentBlack, demoContent.get(), false); diff --git a/examples/DemoRunner/Source/UI/DemoContentComponent.h b/examples/DemoRunner/Source/UI/DemoContentComponent.h index b4daee11..7a15f537 100644 --- a/examples/DemoRunner/Source/UI/DemoContentComponent.h +++ b/examples/DemoRunner/Source/UI/DemoContentComponent.h @@ -26,7 +26,7 @@ #pragma once -#include "../JuceLibraryCode/JuceHeader.h" +#include #include "../Demos/JUCEDemos.h" struct DemoContent; diff --git a/examples/DemoRunner/Source/UI/MainComponent.h b/examples/DemoRunner/Source/UI/MainComponent.h index 5833cb91..24863830 100644 --- a/examples/DemoRunner/Source/UI/MainComponent.h +++ b/examples/DemoRunner/Source/UI/MainComponent.h @@ -26,7 +26,7 @@ #pragma once -#include "../JuceLibraryCode/JuceHeader.h" +#include #include "DemoContentComponent.h" //============================================================================== diff --git a/examples/GUI/FontsDemo.h b/examples/GUI/FontsDemo.h index baeb14d9..035fd8c5 100644 --- a/examples/GUI/FontsDemo.h +++ b/examples/GUI/FontsDemo.h @@ -151,11 +151,13 @@ public: r.removeFromLeft (verticalDividerBar->getRight()); - styleBox.setBounds (r.removeFromBottom (26)); - r.removeFromBottom (8); - int labelWidth = 60; + auto styleArea = r.removeFromBottom (26); + styleArea.removeFromLeft (labelWidth); + styleBox.setBounds (styleArea); + r.removeFromBottom (8); + auto row = r.removeFromBottom (30); row.removeFromLeft (labelWidth); boldToggle.setBounds (row.removeFromLeft (row.getWidth() / 2)); @@ -215,8 +217,8 @@ private: Label heightLabel { {}, "Height:" }, kerningLabel { {}, "Kerning:" }, - scaleLabel { "Scale:" }, - styleLabel { "Style" }; + scaleLabel { {}, "Scale:" }, + styleLabel { {}, "Style:" }; ToggleButton boldToggle { "Bold" }, italicToggle { "Italic" }; diff --git a/examples/GUI/ImagesDemo.h b/examples/GUI/ImagesDemo.h index 61a0e4fe..478bf494 100644 --- a/examples/GUI/ImagesDemo.h +++ b/examples/GUI/ImagesDemo.h @@ -126,7 +126,7 @@ private: if (selectedFile.existsAsFile()) imagePreview.setImage (ImageCache::getFromFile (selectedFile)); - // the image cahce is a handly way to load images from files or directly from memory and + // the image cache is a handy way to load images from files or directly from memory and // will keep them hanging around for a few seconds in case they are requested elsewhere } diff --git a/examples/GUI/MDIDemo.h b/examples/GUI/MDIDemo.h index 040cebb7..7b3c0632 100644 --- a/examples/GUI/MDIDemo.h +++ b/examples/GUI/MDIDemo.h @@ -51,7 +51,7 @@ //============================================================================== /** The Note class contains text editor used to display and edit the note's contents and will also listen to changes in the text and mark the FileBasedDocument as 'dirty'. This 'dirty' - flag is used to promt the user to save the note when it is closed. + flag is used to prompt the user to save the note when it is closed. */ class Note : public Component, public FileBasedDocument diff --git a/examples/GUI/WidgetsDemo.h b/examples/GUI/WidgetsDemo.h index 27a62200..9ee29bcc 100644 --- a/examples/GUI/WidgetsDemo.h +++ b/examples/GUI/WidgetsDemo.h @@ -87,7 +87,12 @@ public: void clicked() override { - auto* colourSelector = new ColourSelector(); + auto* colourSelector = new ColourSelector (ColourSelector::showAlphaChannel + | ColourSelector::showColourAtTop + | ColourSelector::editableColour + | ColourSelector::showSliders + | ColourSelector::showColourspace); + colourSelector->setName ("background"); colourSelector->setCurrentColour (findColour (TextButton::buttonColourId)); colourSelector->addChangeListener (this); @@ -439,6 +444,8 @@ private: OwnedArray components; std::unique_ptr bubbleMessage; + TooltipWindow tooltipWindow; + // This little function avoids a bit of code-duplication by adding a component to // our list as well as calling addAndMakeVisible on it.. template diff --git a/examples/Plugins/InterAppAudioEffectPluginDemo.h b/examples/Plugins/InterAppAudioEffectPluginDemo.h index c159dd58..4b750e86 100644 --- a/examples/Plugins/InterAppAudioEffectPluginDemo.h +++ b/examples/Plugins/InterAppAudioEffectPluginDemo.h @@ -180,7 +180,7 @@ public: void processBlock (AudioBuffer& buffer, MidiBuffer&) override { - auto gain = *parameters.getRawParameterValue ("gain"); + float gain = *parameters.getRawParameterValue ("gain"); auto totalNumInputChannels = getTotalNumInputChannels(); auto totalNumOutputChannels = getTotalNumOutputChannels(); diff --git a/examples/Utilities/InAppPurchasesDemo.h b/examples/Utilities/InAppPurchasesDemo.h index f726acbe..7937857d 100644 --- a/examples/Utilities/InAppPurchasesDemo.h +++ b/examples/Utilities/InAppPurchasesDemo.h @@ -52,6 +52,19 @@ #include "../Assets/DemoUtilities.h" +/* + To finish the setup of this demo, do the following in the Projucer project: + + 1. In the project settings, set the "Bundle Identifier" to com.roli.juceInAppPurchaseSample + 2. In the Android exporter settings, change the following settings: + - "In-App Billing" - Enabled + - "Key Signing: key.store" - path to InAppPurchase.keystore file in examples/Assets/Signing + - "Key Signing: key.store.password" - amazingvoices + - "Key Signing: key-alias" - InAppPurchase + - "Key Signing: key.alias.password" - amazingvoices + 3. Re-save the project +*/ + //============================================================================== class VoicePurchases : private InAppPurchases::Listener { @@ -108,7 +121,7 @@ public: purchaseInProgress = true; product.purchaseInProgress = true; - InAppPurchases::getInstance()->purchaseProduct (product.identifier, false); + InAppPurchases::getInstance()->purchaseProduct (product.identifier); guiUpdater.triggerAsyncUpdate(); } diff --git a/examples/Utilities/SystemInfoDemo.h b/examples/Utilities/SystemInfoDemo.h index 85123712..5e6294e4 100644 --- a/examples/Utilities/SystemInfoDemo.h +++ b/examples/Utilities/SystemInfoDemo.h @@ -149,6 +149,8 @@ static String getAllSystemInfo() << "CPU model: " << SystemStats::getCpuModel() << newLine << "CPU speed: " << SystemStats::getCpuSpeedInMegahertz() << " MHz" << newLine << "CPU has MMX: " << (SystemStats::hasMMX() ? "yes" : "no") << newLine + << "CPU has FMA3: " << (SystemStats::hasFMA3() ? "yes" : "no") << newLine + << "CPU has FMA4: " << (SystemStats::hasFMA4() ? "yes" : "no") << newLine << "CPU has SSE: " << (SystemStats::hasSSE() ? "yes" : "no") << newLine << "CPU has SSE2: " << (SystemStats::hasSSE2() ? "yes" : "no") << newLine << "CPU has SSE3: " << (SystemStats::hasSSE3() ? "yes" : "no") << newLine diff --git a/examples/Utilities/TimersAndEventsDemo.h b/examples/Utilities/TimersAndEventsDemo.h index 01b29a89..56ca48e3 100644 --- a/examples/Utilities/TimersAndEventsDemo.h +++ b/examples/Utilities/TimersAndEventsDemo.h @@ -134,7 +134,7 @@ private: { stopFlashing(); sendChangeMessage(); - // Once we've finsihed flashing send a change message to trigger the next component to flash + // Once we've finished flashing send a change message to trigger the next component to flash } repaint(); @@ -173,7 +173,7 @@ public: addAndMakeVisible (randomColourButton); randomColourButton.onClick = [this] { randomColourButtonClicked(); }; - // lay out our components in a psudo random grid + // lay out our components in a pseudo random grid Rectangle area (0, 100, 150, 150); for (auto* comp : flashingComponents) diff --git a/examples/Utilities/XMLandJSONDemo.h b/examples/Utilities/XMLandJSONDemo.h index 79d18661..b780a1de 100644 --- a/examples/Utilities/XMLandJSONDemo.h +++ b/examples/Utilities/XMLandJSONDemo.h @@ -345,7 +345,7 @@ private: resultsTree.setRootItem (rootItem.get()); } - /** Parses the editors contects as XML. */ + /** Parses the editor's contents as XML. */ TreeViewItem* rebuildXml() { parsedXml.reset(); @@ -368,7 +368,7 @@ private: return new XmlTreeItem (*parsedXml); } - /** Parses the editors contects as JSON. */ + /** Parses the editor's contents as JSON. */ TreeViewItem* rebuildJson() { var parsedJson; diff --git a/extras/AudioPerformanceTest/AudioPerformanceTest.jucer b/extras/AudioPerformanceTest/AudioPerformanceTest.jucer index f030db71..61c0a854 100644 --- a/extras/AudioPerformanceTest/AudioPerformanceTest.jucer +++ b/extras/AudioPerformanceTest/AudioPerformanceTest.jucer @@ -1,7 +1,7 @@ diff --git a/extras/AudioPerformanceTest/Builds/Android/app/CMakeLists.txt b/extras/AudioPerformanceTest/Builds/Android/app/CMakeLists.txt index 90e4d179..762bb07f 100644 --- a/extras/AudioPerformanceTest/Builds/Android/app/CMakeLists.txt +++ b/extras/AudioPerformanceTest/Builds/Android/app/CMakeLists.txt @@ -568,8 +568,6 @@ add_library( ${BINARY_NAME} "../../../../../modules/juce_core/misc/juce_Result.h" "../../../../../modules/juce_core/misc/juce_RuntimePermissions.cpp" "../../../../../modules/juce_core/misc/juce_RuntimePermissions.h" - "../../../../../modules/juce_core/misc/juce_StdFunctionCompat.cpp" - "../../../../../modules/juce_core/misc/juce_StdFunctionCompat.h" "../../../../../modules/juce_core/misc/juce_Uuid.cpp" "../../../../../modules/juce_core/misc/juce_Uuid.h" "../../../../../modules/juce_core/misc/juce_WindowsRegistry.h" @@ -685,6 +683,7 @@ add_library( ${BINARY_NAME} "../../../../../modules/juce_core/threads/juce_ThreadPool.h" "../../../../../modules/juce_core/threads/juce_TimeSliceThread.cpp" "../../../../../modules/juce_core/threads/juce_TimeSliceThread.h" + "../../../../../modules/juce_core/threads/juce_WaitableEvent.cpp" "../../../../../modules/juce_core/threads/juce_WaitableEvent.h" "../../../../../modules/juce_core/time/juce_PerformanceCounter.cpp" "../../../../../modules/juce_core/time/juce_PerformanceCounter.h" @@ -1858,8 +1857,6 @@ set_source_files_properties("../../../../../modules/juce_core/misc/juce_Result.c set_source_files_properties("../../../../../modules/juce_core/misc/juce_Result.h" PROPERTIES HEADER_FILE_ONLY TRUE) set_source_files_properties("../../../../../modules/juce_core/misc/juce_RuntimePermissions.cpp" PROPERTIES HEADER_FILE_ONLY TRUE) set_source_files_properties("../../../../../modules/juce_core/misc/juce_RuntimePermissions.h" PROPERTIES HEADER_FILE_ONLY TRUE) -set_source_files_properties("../../../../../modules/juce_core/misc/juce_StdFunctionCompat.cpp" PROPERTIES HEADER_FILE_ONLY TRUE) -set_source_files_properties("../../../../../modules/juce_core/misc/juce_StdFunctionCompat.h" PROPERTIES HEADER_FILE_ONLY TRUE) set_source_files_properties("../../../../../modules/juce_core/misc/juce_Uuid.cpp" PROPERTIES HEADER_FILE_ONLY TRUE) set_source_files_properties("../../../../../modules/juce_core/misc/juce_Uuid.h" PROPERTIES HEADER_FILE_ONLY TRUE) set_source_files_properties("../../../../../modules/juce_core/misc/juce_WindowsRegistry.h" PROPERTIES HEADER_FILE_ONLY TRUE) @@ -1975,6 +1972,7 @@ set_source_files_properties("../../../../../modules/juce_core/threads/juce_Threa set_source_files_properties("../../../../../modules/juce_core/threads/juce_ThreadPool.h" PROPERTIES HEADER_FILE_ONLY TRUE) set_source_files_properties("../../../../../modules/juce_core/threads/juce_TimeSliceThread.cpp" PROPERTIES HEADER_FILE_ONLY TRUE) set_source_files_properties("../../../../../modules/juce_core/threads/juce_TimeSliceThread.h" PROPERTIES HEADER_FILE_ONLY TRUE) +set_source_files_properties("../../../../../modules/juce_core/threads/juce_WaitableEvent.cpp" PROPERTIES HEADER_FILE_ONLY TRUE) set_source_files_properties("../../../../../modules/juce_core/threads/juce_WaitableEvent.h" PROPERTIES HEADER_FILE_ONLY TRUE) set_source_files_properties("../../../../../modules/juce_core/time/juce_PerformanceCounter.cpp" PROPERTIES HEADER_FILE_ONLY TRUE) set_source_files_properties("../../../../../modules/juce_core/time/juce_PerformanceCounter.h" PROPERTIES HEADER_FILE_ONLY TRUE) diff --git a/extras/AudioPerformanceTest/Builds/Android/app/src/main/AndroidManifest.xml b/extras/AudioPerformanceTest/Builds/Android/app/src/main/AndroidManifest.xml index de868f88..6a6b1118 100644 --- a/extras/AudioPerformanceTest/Builds/Android/app/src/main/AndroidManifest.xml +++ b/extras/AudioPerformanceTest/Builds/Android/app/src/main/AndroidManifest.xml @@ -8,6 +8,7 @@ + + + + + + diff --git a/extras/AudioPerformanceTest/Builds/MacOSX/AudioPerformanceTest.entitlements b/extras/AudioPerformanceTest/Builds/MacOSX/AudioPerformanceTest.entitlements deleted file mode 100644 index 6631ffa6..00000000 --- a/extras/AudioPerformanceTest/Builds/MacOSX/AudioPerformanceTest.entitlements +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/extras/AudioPerformanceTest/Builds/MacOSX/AudioPerformanceTest.xcodeproj/project.pbxproj b/extras/AudioPerformanceTest/Builds/MacOSX/AudioPerformanceTest.xcodeproj/project.pbxproj index 0772d9b1..776ea1e1 100644 --- a/extras/AudioPerformanceTest/Builds/MacOSX/AudioPerformanceTest.xcodeproj/project.pbxproj +++ b/extras/AudioPerformanceTest/Builds/MacOSX/AudioPerformanceTest.xcodeproj/project.pbxproj @@ -336,13 +336,6 @@ path = "../../JuceLibraryCode/include_juce_audio_utils.mm"; sourceTree = "SOURCE_ROOT"; }; - C3BE13F50343166A30728D8A = { - isa = PBXFileReference; - lastKnownFileType = text.plist.xml; - name = AudioPerformanceTest.entitlements; - path = AudioPerformanceTest.entitlements; - sourceTree = "SOURCE_ROOT"; - }; C8EE61FDD1F06817A014B881 = { isa = PBXFileReference; lastKnownFileType = file; @@ -625,6 +618,7 @@ GCC_WARN_UNUSED_VARIABLE = YES; ONLY_ACTIVE_ARCH = YES; PRODUCT_NAME = "AudioPerformanceTest"; + SDKROOT = macosx; WARNING_CFLAGS = "-Wreorder"; ZERO_LINK = NO; }; @@ -670,6 +664,7 @@ GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; PRODUCT_NAME = "AudioPerformanceTest"; + SDKROOT = macosx; WARNING_CFLAGS = "-Wreorder"; ZERO_LINK = NO; }; diff --git a/extras/AudioPerformanceTest/Builds/VisualStudio2019/AudioPerformanceTest_App.vcxproj b/extras/AudioPerformanceTest/Builds/VisualStudio2019/AudioPerformanceTest_App.vcxproj index 7115eb29..8531b492 100644 --- a/extras/AudioPerformanceTest/Builds/VisualStudio2019/AudioPerformanceTest_App.vcxproj +++ b/extras/AudioPerformanceTest/Builds/VisualStudio2019/AudioPerformanceTest_App.vcxproj @@ -751,9 +751,6 @@ true - - true - true @@ -904,6 +901,9 @@ true + + true + true @@ -2165,7 +2165,6 @@ - diff --git a/extras/AudioPerformanceTest/Builds/VisualStudio2019/AudioPerformanceTest_App.vcxproj.filters b/extras/AudioPerformanceTest/Builds/VisualStudio2019/AudioPerformanceTest_App.vcxproj.filters index 3c1483fe..12212e51 100644 --- a/extras/AudioPerformanceTest/Builds/VisualStudio2019/AudioPerformanceTest_App.vcxproj.filters +++ b/extras/AudioPerformanceTest/Builds/VisualStudio2019/AudioPerformanceTest_App.vcxproj.filters @@ -1033,9 +1033,6 @@ JUCE Modules\juce_core\misc - - JUCE Modules\juce_core\misc - JUCE Modules\juce_core\misc @@ -1201,6 +1198,9 @@ JUCE Modules\juce_core\threads + + JUCE Modules\juce_core\threads + JUCE Modules\juce_core\time @@ -3174,9 +3174,6 @@ JUCE Modules\juce_core\misc - - JUCE Modules\juce_core\misc - JUCE Modules\juce_core\misc diff --git a/extras/AudioPerformanceTest/Builds/iOS/App.entitlements b/extras/AudioPerformanceTest/Builds/iOS/App.entitlements new file mode 100644 index 00000000..6631ffa6 --- /dev/null +++ b/extras/AudioPerformanceTest/Builds/iOS/App.entitlements @@ -0,0 +1,6 @@ + + + + + + diff --git a/extras/AudioPerformanceTest/Builds/iOS/AudioPerformanceTest.entitlements b/extras/AudioPerformanceTest/Builds/iOS/AudioPerformanceTest.entitlements deleted file mode 100644 index 6631ffa6..00000000 --- a/extras/AudioPerformanceTest/Builds/iOS/AudioPerformanceTest.entitlements +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/extras/AudioPerformanceTest/Builds/iOS/AudioPerformanceTest.xcodeproj/project.pbxproj b/extras/AudioPerformanceTest/Builds/iOS/AudioPerformanceTest.xcodeproj/project.pbxproj index 979f3567..54933a53 100644 --- a/extras/AudioPerformanceTest/Builds/iOS/AudioPerformanceTest.xcodeproj/project.pbxproj +++ b/extras/AudioPerformanceTest/Builds/iOS/AudioPerformanceTest.xcodeproj/project.pbxproj @@ -355,13 +355,6 @@ path = "../../JuceLibraryCode/include_juce_audio_utils.mm"; sourceTree = "SOURCE_ROOT"; }; - C3BE13F50343166A30728D8A = { - isa = PBXFileReference; - lastKnownFileType = text.plist.xml; - name = AudioPerformanceTest.entitlements; - path = AudioPerformanceTest.entitlements; - sourceTree = "SOURCE_ROOT"; - }; C6030BFC7A19A5075AB0EC28 = { isa = PBXFileReference; lastKnownFileType = wrapper.framework; diff --git a/extras/AudioPerformanceTest/JuceLibraryCode/AppConfig.h b/extras/AudioPerformanceTest/JuceLibraryCode/AppConfig.h index 9032f6ee..c03b022d 100644 --- a/extras/AudioPerformanceTest/JuceLibraryCode/AppConfig.h +++ b/extras/AudioPerformanceTest/JuceLibraryCode/AppConfig.h @@ -47,7 +47,7 @@ #define JUCE_USE_DARK_SPLASH_SCREEN 1 -#define JUCE_PROJUCER_VERSION 0x50405 +#define JUCE_PROJUCER_VERSION 0x50406 //============================================================================== #define JUCE_MODULE_AVAILABLE_juce_audio_basics 1 @@ -210,8 +210,8 @@ //============================================================================== // juce_events flags: -#ifndef JUCE_EXECUTE_APP_SUSPEND_ON_IOS_BACKGROUND_TASK - //#define JUCE_EXECUTE_APP_SUSPEND_ON_IOS_BACKGROUND_TASK 0 +#ifndef JUCE_EXECUTE_APP_SUSPEND_ON_BACKGROUND_TASK + //#define JUCE_EXECUTE_APP_SUSPEND_ON_BACKGROUND_TASK 0 #endif //============================================================================== diff --git a/extras/AudioPerformanceTest/Source/Main.cpp b/extras/AudioPerformanceTest/Source/Main.cpp index bfce625b..76c3337f 100644 --- a/extras/AudioPerformanceTest/Source/Main.cpp +++ b/extras/AudioPerformanceTest/Source/Main.cpp @@ -24,7 +24,7 @@ ============================================================================== */ -#include "../JuceLibraryCode/JuceHeader.h" +#include #include "MainComponent.h" Component* createMainContentComponent(); diff --git a/extras/AudioPerformanceTest/Source/MainComponent.h b/extras/AudioPerformanceTest/Source/MainComponent.h index f30b83e4..73dc3a18 100644 --- a/extras/AudioPerformanceTest/Source/MainComponent.h +++ b/extras/AudioPerformanceTest/Source/MainComponent.h @@ -26,7 +26,7 @@ #pragma once -#include "../JuceLibraryCode/JuceHeader.h" +#include #include //============================================================================== diff --git a/extras/AudioPluginHost/AudioPluginHost.jucer b/extras/AudioPluginHost/AudioPluginHost.jucer index 8ace7ccf..ac227ba1 100644 --- a/extras/AudioPluginHost/AudioPluginHost.jucer +++ b/extras/AudioPluginHost/AudioPluginHost.jucer @@ -2,7 +2,7 @@ - + diff --git a/extras/AudioPluginHost/Builds/Android/app/CMakeLists.txt b/extras/AudioPluginHost/Builds/Android/app/CMakeLists.txt index e2174833..eded0ed7 100644 --- a/extras/AudioPluginHost/Builds/Android/app/CMakeLists.txt +++ b/extras/AudioPluginHost/Builds/Android/app/CMakeLists.txt @@ -585,8 +585,6 @@ add_library( ${BINARY_NAME} "../../../../../modules/juce_core/misc/juce_Result.h" "../../../../../modules/juce_core/misc/juce_RuntimePermissions.cpp" "../../../../../modules/juce_core/misc/juce_RuntimePermissions.h" - "../../../../../modules/juce_core/misc/juce_StdFunctionCompat.cpp" - "../../../../../modules/juce_core/misc/juce_StdFunctionCompat.h" "../../../../../modules/juce_core/misc/juce_Uuid.cpp" "../../../../../modules/juce_core/misc/juce_Uuid.h" "../../../../../modules/juce_core/misc/juce_WindowsRegistry.h" @@ -702,6 +700,7 @@ add_library( ${BINARY_NAME} "../../../../../modules/juce_core/threads/juce_ThreadPool.h" "../../../../../modules/juce_core/threads/juce_TimeSliceThread.cpp" "../../../../../modules/juce_core/threads/juce_TimeSliceThread.h" + "../../../../../modules/juce_core/threads/juce_WaitableEvent.cpp" "../../../../../modules/juce_core/threads/juce_WaitableEvent.h" "../../../../../modules/juce_core/time/juce_PerformanceCounter.cpp" "../../../../../modules/juce_core/time/juce_PerformanceCounter.h" @@ -1948,8 +1947,6 @@ set_source_files_properties("../../../../../modules/juce_core/misc/juce_Result.c set_source_files_properties("../../../../../modules/juce_core/misc/juce_Result.h" PROPERTIES HEADER_FILE_ONLY TRUE) set_source_files_properties("../../../../../modules/juce_core/misc/juce_RuntimePermissions.cpp" PROPERTIES HEADER_FILE_ONLY TRUE) set_source_files_properties("../../../../../modules/juce_core/misc/juce_RuntimePermissions.h" PROPERTIES HEADER_FILE_ONLY TRUE) -set_source_files_properties("../../../../../modules/juce_core/misc/juce_StdFunctionCompat.cpp" PROPERTIES HEADER_FILE_ONLY TRUE) -set_source_files_properties("../../../../../modules/juce_core/misc/juce_StdFunctionCompat.h" PROPERTIES HEADER_FILE_ONLY TRUE) set_source_files_properties("../../../../../modules/juce_core/misc/juce_Uuid.cpp" PROPERTIES HEADER_FILE_ONLY TRUE) set_source_files_properties("../../../../../modules/juce_core/misc/juce_Uuid.h" PROPERTIES HEADER_FILE_ONLY TRUE) set_source_files_properties("../../../../../modules/juce_core/misc/juce_WindowsRegistry.h" PROPERTIES HEADER_FILE_ONLY TRUE) @@ -2065,6 +2062,7 @@ set_source_files_properties("../../../../../modules/juce_core/threads/juce_Threa set_source_files_properties("../../../../../modules/juce_core/threads/juce_ThreadPool.h" PROPERTIES HEADER_FILE_ONLY TRUE) set_source_files_properties("../../../../../modules/juce_core/threads/juce_TimeSliceThread.cpp" PROPERTIES HEADER_FILE_ONLY TRUE) set_source_files_properties("../../../../../modules/juce_core/threads/juce_TimeSliceThread.h" PROPERTIES HEADER_FILE_ONLY TRUE) +set_source_files_properties("../../../../../modules/juce_core/threads/juce_WaitableEvent.cpp" PROPERTIES HEADER_FILE_ONLY TRUE) set_source_files_properties("../../../../../modules/juce_core/threads/juce_WaitableEvent.h" PROPERTIES HEADER_FILE_ONLY TRUE) set_source_files_properties("../../../../../modules/juce_core/time/juce_PerformanceCounter.cpp" PROPERTIES HEADER_FILE_ONLY TRUE) set_source_files_properties("../../../../../modules/juce_core/time/juce_PerformanceCounter.h" PROPERTIES HEADER_FILE_ONLY TRUE) diff --git a/extras/AudioPluginHost/Builds/Android/app/src/main/AndroidManifest.xml b/extras/AudioPluginHost/Builds/Android/app/src/main/AndroidManifest.xml index a81c4764..bc704681 100644 --- a/extras/AudioPluginHost/Builds/Android/app/src/main/AndroidManifest.xml +++ b/extras/AudioPluginHost/Builds/Android/app/src/main/AndroidManifest.xml @@ -9,6 +9,7 @@ + diff --git a/extras/AudioPluginHost/Builds/Android/build.gradle b/extras/AudioPluginHost/Builds/Android/build.gradle index 2df9a8e7..cfd3a2f8 100644 --- a/extras/AudioPluginHost/Builds/Android/build.gradle +++ b/extras/AudioPluginHost/Builds/Android/build.gradle @@ -4,7 +4,7 @@ buildscript { jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:3.2.1' + classpath 'com.android.tools.build:gradle:3.5.3' } } diff --git a/extras/AudioPluginHost/Builds/Android/gradle/wrapper/gradle-wrapper.properties b/extras/AudioPluginHost/Builds/Android/gradle/wrapper/gradle-wrapper.properties index b460908d..b66802c7 100644 --- a/extras/AudioPluginHost/Builds/Android/gradle/wrapper/gradle-wrapper.properties +++ b/extras/AudioPluginHost/Builds/Android/gradle/wrapper/gradle-wrapper.properties @@ -1 +1 @@ -distributionUrl=https\://services.gradle.org/distributions/gradle-4.10-all.zip \ No newline at end of file +distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip \ No newline at end of file diff --git a/extras/AudioPluginHost/Builds/MacOSX/App.entitlements b/extras/AudioPluginHost/Builds/MacOSX/App.entitlements new file mode 100644 index 00000000..6631ffa6 --- /dev/null +++ b/extras/AudioPluginHost/Builds/MacOSX/App.entitlements @@ -0,0 +1,6 @@ + + + + + + diff --git a/extras/AudioPluginHost/Builds/MacOSX/AudioPluginHost.entitlements b/extras/AudioPluginHost/Builds/MacOSX/AudioPluginHost.entitlements deleted file mode 100644 index 6631ffa6..00000000 --- a/extras/AudioPluginHost/Builds/MacOSX/AudioPluginHost.entitlements +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/extras/AudioPluginHost/Builds/MacOSX/AudioPluginHost.xcodeproj/project.pbxproj b/extras/AudioPluginHost/Builds/MacOSX/AudioPluginHost.xcodeproj/project.pbxproj index 8ba981fe..9afcda35 100644 --- a/extras/AudioPluginHost/Builds/MacOSX/AudioPluginHost.xcodeproj/project.pbxproj +++ b/extras/AudioPluginHost/Builds/MacOSX/AudioPluginHost.xcodeproj/project.pbxproj @@ -9,6 +9,10 @@ isa = PBXBuildFile; fileRef = 8D8BBC353637DA442C5575DA; }; + B288A89F96704F142ED8E939 = { + isa = PBXBuildFile; + fileRef = 5ACC21AA45BBF48C3C64D56D; + }; 73E371F1B912FCCAE0CD7E5D = { isa = PBXBuildFile; fileRef = 86CA337014D3F67E906FFD28; @@ -17,10 +21,6 @@ isa = PBXBuildFile; fileRef = D4EBC17BDB7F88CCBC76730B; }; - B288A89F96704F142ED8E939 = { - isa = PBXBuildFile; - fileRef = 5ACC21AA45BBF48C3C64D56D; - }; 851C1165C9E4ACDD19C56A96 = { isa = PBXBuildFile; fileRef = 942A0F04EFB8D0B2FF9780BA; @@ -585,13 +585,6 @@ path = System/Library/Frameworks/CoreAudioKit.framework; sourceTree = SDKROOT; }; - EC252E34CF52A70B4A836BDC = { - isa = PBXFileReference; - lastKnownFileType = text.plist.xml; - name = AudioPluginHost.entitlements; - path = AudioPluginHost.entitlements; - sourceTree = "SOURCE_ROOT"; - }; F14CDB17EFE157DA3C3A5A91 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; @@ -730,9 +723,9 @@ D1C4804CD275CB57A5C89A2D = { isa = PBXGroup; children = ( + 5ACC21AA45BBF48C3C64D56D, 86CA337014D3F67E906FFD28, D4EBC17BDB7F88CCBC76730B, - 5ACC21AA45BBF48C3C64D56D, 942A0F04EFB8D0B2FF9780BA, A4B568E26157FC282214976F, B0935EBBA4F6E2B05F3D1C0A, @@ -905,6 +898,7 @@ GCC_WARN_UNUSED_VARIABLE = YES; ONLY_ACTIVE_ARCH = YES; PRODUCT_NAME = "AudioPluginHost"; + SDKROOT = macosx; WARNING_CFLAGS = "-Wreorder"; ZERO_LINK = NO; }; @@ -950,6 +944,7 @@ GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; PRODUCT_NAME = "AudioPluginHost"; + SDKROOT = macosx; WARNING_CFLAGS = "-Wreorder"; ZERO_LINK = NO; }; @@ -1018,9 +1013,9 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + B288A89F96704F142ED8E939, 73E371F1B912FCCAE0CD7E5D, 21D330A5B13178B12BEAFC3C, - B288A89F96704F142ED8E939, 851C1165C9E4ACDD19C56A96, AF42316D915057E930A5624E, 2B4B9CF71F94BDD1E3AC89AE, diff --git a/extras/AudioPluginHost/Builds/VisualStudio2015/AudioPluginHost_App.vcxproj b/extras/AudioPluginHost/Builds/VisualStudio2015/AudioPluginHost_App.vcxproj index a65519c4..8436bc80 100644 --- a/extras/AudioPluginHost/Builds/VisualStudio2015/AudioPluginHost_App.vcxproj +++ b/extras/AudioPluginHost/Builds/VisualStudio2015/AudioPluginHost_App.vcxproj @@ -758,9 +758,6 @@ true - - true - true @@ -911,6 +908,9 @@ true + + true + true @@ -2241,7 +2241,6 @@ - diff --git a/extras/AudioPluginHost/Builds/VisualStudio2015/AudioPluginHost_App.vcxproj.filters b/extras/AudioPluginHost/Builds/VisualStudio2015/AudioPluginHost_App.vcxproj.filters index 74ef99ca..f60af172 100644 --- a/extras/AudioPluginHost/Builds/VisualStudio2015/AudioPluginHost_App.vcxproj.filters +++ b/extras/AudioPluginHost/Builds/VisualStudio2015/AudioPluginHost_App.vcxproj.filters @@ -1090,9 +1090,6 @@ JUCE Modules\juce_core\misc - - JUCE Modules\juce_core\misc - JUCE Modules\juce_core\misc @@ -1258,6 +1255,9 @@ JUCE Modules\juce_core\threads + + JUCE Modules\juce_core\threads + JUCE Modules\juce_core\time @@ -3327,9 +3327,6 @@ JUCE Modules\juce_core\misc - - JUCE Modules\juce_core\misc - JUCE Modules\juce_core\misc diff --git a/extras/AudioPluginHost/Builds/VisualStudio2017/AudioPluginHost_App.vcxproj b/extras/AudioPluginHost/Builds/VisualStudio2017/AudioPluginHost_App.vcxproj index 630e31bd..2a305ff4 100644 --- a/extras/AudioPluginHost/Builds/VisualStudio2017/AudioPluginHost_App.vcxproj +++ b/extras/AudioPluginHost/Builds/VisualStudio2017/AudioPluginHost_App.vcxproj @@ -758,9 +758,6 @@ true - - true - true @@ -911,6 +908,9 @@ true + + true + true @@ -2241,7 +2241,6 @@ - diff --git a/extras/AudioPluginHost/Builds/VisualStudio2017/AudioPluginHost_App.vcxproj.filters b/extras/AudioPluginHost/Builds/VisualStudio2017/AudioPluginHost_App.vcxproj.filters index 3d2f4476..a94fc227 100644 --- a/extras/AudioPluginHost/Builds/VisualStudio2017/AudioPluginHost_App.vcxproj.filters +++ b/extras/AudioPluginHost/Builds/VisualStudio2017/AudioPluginHost_App.vcxproj.filters @@ -1090,9 +1090,6 @@ JUCE Modules\juce_core\misc - - JUCE Modules\juce_core\misc - JUCE Modules\juce_core\misc @@ -1258,6 +1255,9 @@ JUCE Modules\juce_core\threads + + JUCE Modules\juce_core\threads + JUCE Modules\juce_core\time @@ -3327,9 +3327,6 @@ JUCE Modules\juce_core\misc - - JUCE Modules\juce_core\misc - JUCE Modules\juce_core\misc diff --git a/extras/AudioPluginHost/Builds/VisualStudio2019/AudioPluginHost_App.vcxproj b/extras/AudioPluginHost/Builds/VisualStudio2019/AudioPluginHost_App.vcxproj index 007c667c..81848a76 100644 --- a/extras/AudioPluginHost/Builds/VisualStudio2019/AudioPluginHost_App.vcxproj +++ b/extras/AudioPluginHost/Builds/VisualStudio2019/AudioPluginHost_App.vcxproj @@ -758,9 +758,6 @@ true - - true - true @@ -911,6 +908,9 @@ true + + true + true @@ -2241,7 +2241,6 @@ - diff --git a/extras/AudioPluginHost/Builds/VisualStudio2019/AudioPluginHost_App.vcxproj.filters b/extras/AudioPluginHost/Builds/VisualStudio2019/AudioPluginHost_App.vcxproj.filters index 3b679132..adc0637e 100644 --- a/extras/AudioPluginHost/Builds/VisualStudio2019/AudioPluginHost_App.vcxproj.filters +++ b/extras/AudioPluginHost/Builds/VisualStudio2019/AudioPluginHost_App.vcxproj.filters @@ -1090,9 +1090,6 @@ JUCE Modules\juce_core\misc - - JUCE Modules\juce_core\misc - JUCE Modules\juce_core\misc @@ -1258,6 +1255,9 @@ JUCE Modules\juce_core\threads + + JUCE Modules\juce_core\threads + JUCE Modules\juce_core\time @@ -3327,9 +3327,6 @@ JUCE Modules\juce_core\misc - - JUCE Modules\juce_core\misc - JUCE Modules\juce_core\misc diff --git a/extras/AudioPluginHost/Builds/iOS/App.entitlements b/extras/AudioPluginHost/Builds/iOS/App.entitlements new file mode 100644 index 00000000..6631ffa6 --- /dev/null +++ b/extras/AudioPluginHost/Builds/iOS/App.entitlements @@ -0,0 +1,6 @@ + + + + + + diff --git a/extras/AudioPluginHost/Builds/iOS/AudioPluginHost.entitlements b/extras/AudioPluginHost/Builds/iOS/AudioPluginHost.entitlements deleted file mode 100644 index 6631ffa6..00000000 --- a/extras/AudioPluginHost/Builds/iOS/AudioPluginHost.entitlements +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/extras/AudioPluginHost/Builds/iOS/AudioPluginHost.xcodeproj/project.pbxproj b/extras/AudioPluginHost/Builds/iOS/AudioPluginHost.xcodeproj/project.pbxproj index 56ef09ea..9cfd7dea 100644 --- a/extras/AudioPluginHost/Builds/iOS/AudioPluginHost.xcodeproj/project.pbxproj +++ b/extras/AudioPluginHost/Builds/iOS/AudioPluginHost.xcodeproj/project.pbxproj @@ -582,13 +582,6 @@ path = System/Library/Frameworks/CoreAudioKit.framework; sourceTree = SDKROOT; }; - EC252E34CF52A70B4A836BDC = { - isa = PBXFileReference; - lastKnownFileType = text.plist.xml; - name = AudioPluginHost.entitlements; - path = AudioPluginHost.entitlements; - sourceTree = "SOURCE_ROOT"; - }; F14CDB17EFE157DA3C3A5A91 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; diff --git a/extras/AudioPluginHost/JuceLibraryCode/AppConfig.h b/extras/AudioPluginHost/JuceLibraryCode/AppConfig.h index 0a43cec5..f14dc27f 100644 --- a/extras/AudioPluginHost/JuceLibraryCode/AppConfig.h +++ b/extras/AudioPluginHost/JuceLibraryCode/AppConfig.h @@ -49,7 +49,7 @@ #define JUCE_USE_DARK_SPLASH_SCREEN 1 -#define JUCE_PROJUCER_VERSION 0x50405 +#define JUCE_PROJUCER_VERSION 0x50406 //============================================================================== #define JUCE_MODULE_AVAILABLE_juce_audio_basics 1 @@ -215,8 +215,8 @@ //============================================================================== // juce_events flags: -#ifndef JUCE_EXECUTE_APP_SUSPEND_ON_IOS_BACKGROUND_TASK - //#define JUCE_EXECUTE_APP_SUSPEND_ON_IOS_BACKGROUND_TASK 0 +#ifndef JUCE_EXECUTE_APP_SUSPEND_ON_BACKGROUND_TASK + //#define JUCE_EXECUTE_APP_SUSPEND_ON_BACKGROUND_TASK 0 #endif //============================================================================== diff --git a/extras/AudioPluginHost/Source/HostStartup.cpp b/extras/AudioPluginHost/Source/HostStartup.cpp index e45009ac..cce530eb 100644 --- a/extras/AudioPluginHost/Source/HostStartup.cpp +++ b/extras/AudioPluginHost/Source/HostStartup.cpp @@ -24,7 +24,7 @@ ============================================================================== */ -#include "../JuceLibraryCode/JuceHeader.h" +#include #include "UI/MainHostWindow.h" #include "Plugins/InternalPlugins.h" diff --git a/extras/AudioPluginHost/Source/Plugins/IOConfigurationWindow.cpp b/extras/AudioPluginHost/Source/Plugins/IOConfigurationWindow.cpp index 2a8ac4d0..03b34541 100644 --- a/extras/AudioPluginHost/Source/Plugins/IOConfigurationWindow.cpp +++ b/extras/AudioPluginHost/Source/Plugins/IOConfigurationWindow.cpp @@ -24,7 +24,7 @@ ============================================================================== */ -#include "../JuceLibraryCode/JuceHeader.h" +#include #include "../UI/GraphEditorPanel.h" #include "InternalPlugins.h" #include "../UI/MainHostWindow.h" diff --git a/extras/AudioPluginHost/Source/Plugins/InternalPlugins.cpp b/extras/AudioPluginHost/Source/Plugins/InternalPlugins.cpp index ac887559..eb10b98b 100644 --- a/extras/AudioPluginHost/Source/Plugins/InternalPlugins.cpp +++ b/extras/AudioPluginHost/Source/Plugins/InternalPlugins.cpp @@ -24,7 +24,7 @@ ============================================================================== */ -#include "../JuceLibraryCode/JuceHeader.h" +#include #include "InternalPlugins.h" #include "PluginGraph.h" @@ -357,6 +357,11 @@ InternalPluginFormat::InternalPluginFormat() AudioProcessorGraph::AudioGraphIOProcessor p (AudioProcessorGraph::AudioGraphIOProcessor::midiInputNode); p.fillInPluginDescription (midiInDesc); } + + { + AudioProcessorGraph::AudioGraphIOProcessor p (AudioProcessorGraph::AudioGraphIOProcessor::midiOutputNode); + p.fillInPluginDescription (midiOutDesc); + } } std::unique_ptr InternalPluginFormat::createInstance (const String& name) @@ -364,6 +369,7 @@ std::unique_ptr InternalPluginFormat::createInstance (const if (name == audioOutDesc.name) return std::make_unique (AudioProcessorGraph::AudioGraphIOProcessor::audioOutputNode); if (name == audioInDesc.name) return std::make_unique (AudioProcessorGraph::AudioGraphIOProcessor::audioInputNode); if (name == midiInDesc.name) return std::make_unique (AudioProcessorGraph::AudioGraphIOProcessor::midiInputNode); + if (name == midiOutDesc.name) return std::make_unique (AudioProcessorGraph::AudioGraphIOProcessor::midiOutputNode); if (name == SineWaveSynth::getIdentifier()) return std::make_unique (SineWaveSynth::getPluginDescription()); if (name == ReverbPlugin::getIdentifier()) return std::make_unique (ReverbPlugin::getPluginDescription()); @@ -388,7 +394,6 @@ bool InternalPluginFormat::requiresUnblockedMessageThreadDuringCreation (const P void InternalPluginFormat::getAllTypes (Array& results) { - results.add (audioInDesc, audioOutDesc, midiInDesc, - SineWaveSynth::getPluginDescription(), - ReverbPlugin::getPluginDescription()); + results.add (audioInDesc, audioOutDesc, midiInDesc, midiOutDesc, + SineWaveSynth::getPluginDescription(), ReverbPlugin::getPluginDescription()); } diff --git a/extras/AudioPluginHost/Source/Plugins/InternalPlugins.h b/extras/AudioPluginHost/Source/Plugins/InternalPlugins.h index 82baf6e7..b5282a09 100644 --- a/extras/AudioPluginHost/Source/Plugins/InternalPlugins.h +++ b/extras/AudioPluginHost/Source/Plugins/InternalPlugins.h @@ -41,7 +41,7 @@ public: ~InternalPluginFormat() override {} //============================================================================== - PluginDescription audioInDesc, audioOutDesc, midiInDesc; + PluginDescription audioInDesc, audioOutDesc, midiInDesc, midiOutDesc; void getAllTypes (Array&); //============================================================================== diff --git a/extras/AudioPluginHost/Source/Plugins/PluginGraph.cpp b/extras/AudioPluginHost/Source/Plugins/PluginGraph.cpp index 082911e5..8d9b9261 100644 --- a/extras/AudioPluginHost/Source/Plugins/PluginGraph.cpp +++ b/extras/AudioPluginHost/Source/Plugins/PluginGraph.cpp @@ -24,7 +24,7 @@ ============================================================================== */ -#include "../JuceLibraryCode/JuceHeader.h" +#include #include "../UI/MainHostWindow.h" #include "PluginGraph.h" #include "InternalPlugins.h" @@ -202,11 +202,13 @@ void PluginGraph::newDocument() addPlugin (internalFormat.audioInDesc, { 0.5, 0.1 }); addPlugin (internalFormat.midiInDesc, { 0.25, 0.1 }); addPlugin (internalFormat.audioOutDesc, { 0.5, 0.9 }); + addPlugin (internalFormat.midiOutDesc, { 0.25, 0.9 }); - MessageManager::callAsync ([this] () { + MessageManager::callAsync ([this] + { setChangedFlag (false); graph.addChangeListener (this); - } ); + }); } Result PluginGraph::loadDocument (const File& file) diff --git a/extras/AudioPluginHost/Source/UI/GraphEditorPanel.cpp b/extras/AudioPluginHost/Source/UI/GraphEditorPanel.cpp index a74497f6..afa65bdb 100644 --- a/extras/AudioPluginHost/Source/UI/GraphEditorPanel.cpp +++ b/extras/AudioPluginHost/Source/UI/GraphEditorPanel.cpp @@ -24,7 +24,7 @@ ============================================================================== */ -#include "../JuceLibraryCode/JuceHeader.h" +#include #include "GraphEditorPanel.h" #include "../Plugins/InternalPlugins.h" #include "MainHostWindow.h" @@ -1167,10 +1167,13 @@ GraphDocumentComponent::GraphDocumentComponent (AudioPluginFormatManager& fm, deviceManager.addChangeListener (graphPanel.get()); deviceManager.addAudioCallback (&graphPlayer); deviceManager.addMidiInputDeviceCallback ({}, &graphPlayer.getMidiMessageCollector()); + deviceManager.addChangeListener (this); } void GraphDocumentComponent::init() { + updateMidiOutput(); + graphPanel.reset (new GraphEditorPanel (*graph)); addAndMakeVisible (graphPanel.get()); graphPlayer.setProcessor (&graph->graph); @@ -1213,6 +1216,9 @@ void GraphDocumentComponent::init() GraphDocumentComponent::~GraphDocumentComponent() { + if (midiOutput != nullptr) + midiOutput->stopBackgroundThread(); + releaseGraph(); keyState.removeListener (&graphPlayer.getMidiMessageCollector()); @@ -1326,3 +1332,23 @@ bool GraphDocumentComponent::closeAnyOpenPluginWindows() { return graphPanel->graph.closeAnyOpenPluginWindows(); } + +void GraphDocumentComponent::changeListenerCallback (ChangeBroadcaster*) +{ + updateMidiOutput(); +} + +void GraphDocumentComponent::updateMidiOutput() +{ + auto* defaultMidiOutput = deviceManager.getDefaultMidiOutput(); + + if (midiOutput != defaultMidiOutput) + { + midiOutput = defaultMidiOutput; + + if (midiOutput != nullptr) + midiOutput->startBackgroundThread(); + + graphPlayer.setMidiOutput (midiOutput); + } +} diff --git a/extras/AudioPluginHost/Source/UI/GraphEditorPanel.h b/extras/AudioPluginHost/Source/UI/GraphEditorPanel.h index 2796b750..f5a5a6cc 100644 --- a/extras/AudioPluginHost/Source/UI/GraphEditorPanel.h +++ b/extras/AudioPluginHost/Source/UI/GraphEditorPanel.h @@ -100,7 +100,8 @@ private: */ class GraphDocumentComponent : public Component, public DragAndDropTarget, - public DragAndDropContainer + public DragAndDropContainer, + private ChangeListener { public: GraphDocumentComponent (AudioPluginFormatManager& formatManager, @@ -142,6 +143,7 @@ private: AudioProcessorPlayer graphPlayer; MidiKeyboardState keyState; + MidiOutput* midiOutput = nullptr; struct TooltipBar; std::unique_ptr statusBar; @@ -160,8 +162,11 @@ private: SidePanel* lastOpenedSidePanel = nullptr; //============================================================================== + void changeListenerCallback (ChangeBroadcaster*) override; + void init(); void checkAvailableWidth(); + void updateMidiOutput(); //============================================================================== JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (GraphDocumentComponent) diff --git a/extras/AudioPluginHost/Source/UI/MainHostWindow.cpp b/extras/AudioPluginHost/Source/UI/MainHostWindow.cpp index 28678c2c..104b8aae 100644 --- a/extras/AudioPluginHost/Source/UI/MainHostWindow.cpp +++ b/extras/AudioPluginHost/Source/UI/MainHostWindow.cpp @@ -24,7 +24,7 @@ ============================================================================== */ -#include "../JuceLibraryCode/JuceHeader.h" +#include #include "MainHostWindow.h" #include "../Plugins/InternalPlugins.h" diff --git a/extras/AudioPluginHost/Source/UI/PluginWindow.h b/extras/AudioPluginHost/Source/UI/PluginWindow.h index e2abee46..ac1af990 100644 --- a/extras/AudioPluginHost/Source/UI/PluginWindow.h +++ b/extras/AudioPluginHost/Source/UI/PluginWindow.h @@ -31,7 +31,7 @@ class PluginGraph; /** - A window that shows a log of parameter change messagse sent by the plugin. + A window that shows a log of parameter change messages sent by the plugin. */ class PluginDebugWindow : public AudioProcessorEditor, public AudioProcessorParameter::Listener, diff --git a/extras/BinaryBuilder/BinaryBuilder.jucer b/extras/BinaryBuilder/BinaryBuilder.jucer index 8c13340b..ada60fc1 100644 --- a/extras/BinaryBuilder/BinaryBuilder.jucer +++ b/extras/BinaryBuilder/BinaryBuilder.jucer @@ -1,7 +1,7 @@ diff --git a/extras/BinaryBuilder/Builds/MacOSX/BinaryBuilder.entitlements b/extras/BinaryBuilder/Builds/MacOSX/BinaryBuilder.entitlements deleted file mode 100644 index 6631ffa6..00000000 --- a/extras/BinaryBuilder/Builds/MacOSX/BinaryBuilder.entitlements +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/extras/BinaryBuilder/Builds/MacOSX/BinaryBuilder.xcodeproj/project.pbxproj b/extras/BinaryBuilder/Builds/MacOSX/BinaryBuilder.xcodeproj/project.pbxproj index 479760bf..557784d5 100644 --- a/extras/BinaryBuilder/Builds/MacOSX/BinaryBuilder.xcodeproj/project.pbxproj +++ b/extras/BinaryBuilder/Builds/MacOSX/BinaryBuilder.xcodeproj/project.pbxproj @@ -36,13 +36,6 @@ path = RecentFilesMenuTemplate.nib; sourceTree = "SOURCE_ROOT"; }; - 25C3A81567A43C28D8A9C143 = { - isa = PBXFileReference; - lastKnownFileType = text.plist.xml; - name = BinaryBuilder.entitlements; - path = BinaryBuilder.entitlements; - sourceTree = "SOURCE_ROOT"; - }; 50B7C64414A3E778021F5EC4 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; @@ -297,6 +290,7 @@ GCC_WARN_UNUSED_VARIABLE = YES; ONLY_ACTIVE_ARCH = YES; PRODUCT_NAME = "BinaryBuilder"; + SDKROOT = macosx; WARNING_CFLAGS = "-Wreorder"; ZERO_LINK = NO; }; @@ -342,6 +336,7 @@ GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; PRODUCT_NAME = "BinaryBuilder"; + SDKROOT = macosx; WARNING_CFLAGS = "-Wreorder"; ZERO_LINK = NO; }; diff --git a/extras/BinaryBuilder/Builds/MacOSX/ConsoleApp.entitlements b/extras/BinaryBuilder/Builds/MacOSX/ConsoleApp.entitlements new file mode 100644 index 00000000..6631ffa6 --- /dev/null +++ b/extras/BinaryBuilder/Builds/MacOSX/ConsoleApp.entitlements @@ -0,0 +1,6 @@ + + + + + + diff --git a/extras/BinaryBuilder/Builds/VisualStudio2019/BinaryBuilder_ConsoleApp.vcxproj b/extras/BinaryBuilder/Builds/VisualStudio2019/BinaryBuilder_ConsoleApp.vcxproj index 34d798a8..7e823639 100644 --- a/extras/BinaryBuilder/Builds/VisualStudio2019/BinaryBuilder_ConsoleApp.vcxproj +++ b/extras/BinaryBuilder/Builds/VisualStudio2019/BinaryBuilder_ConsoleApp.vcxproj @@ -226,9 +226,6 @@ true - - true - true @@ -379,6 +376,9 @@ true + + true + true @@ -499,7 +499,6 @@ - diff --git a/extras/BinaryBuilder/Builds/VisualStudio2019/BinaryBuilder_ConsoleApp.vcxproj.filters b/extras/BinaryBuilder/Builds/VisualStudio2019/BinaryBuilder_ConsoleApp.vcxproj.filters index ce4e94ce..98e83714 100644 --- a/extras/BinaryBuilder/Builds/VisualStudio2019/BinaryBuilder_ConsoleApp.vcxproj.filters +++ b/extras/BinaryBuilder/Builds/VisualStudio2019/BinaryBuilder_ConsoleApp.vcxproj.filters @@ -166,9 +166,6 @@ JUCE Modules\juce_core\misc - - JUCE Modules\juce_core\misc - JUCE Modules\juce_core\misc @@ -334,6 +331,9 @@ JUCE Modules\juce_core\threads + + JUCE Modules\juce_core\threads + JUCE Modules\juce_core\time @@ -567,9 +567,6 @@ JUCE Modules\juce_core\misc - - JUCE Modules\juce_core\misc - JUCE Modules\juce_core\misc diff --git a/extras/BinaryBuilder/JuceLibraryCode/AppConfig.h b/extras/BinaryBuilder/JuceLibraryCode/AppConfig.h index ee326c03..8fcbef4a 100644 --- a/extras/BinaryBuilder/JuceLibraryCode/AppConfig.h +++ b/extras/BinaryBuilder/JuceLibraryCode/AppConfig.h @@ -47,7 +47,7 @@ #define JUCE_USE_DARK_SPLASH_SCREEN 1 -#define JUCE_PROJUCER_VERSION 0x50405 +#define JUCE_PROJUCER_VERSION 0x50406 //============================================================================== #define JUCE_MODULE_AVAILABLE_juce_core 1 diff --git a/extras/BinaryBuilder/Source/Main.cpp b/extras/BinaryBuilder/Source/Main.cpp index e6c4aeaa..9716d7c1 100644 --- a/extras/BinaryBuilder/Source/Main.cpp +++ b/extras/BinaryBuilder/Source/Main.cpp @@ -35,7 +35,7 @@ ============================================================================== */ -#include "../JuceLibraryCode/JuceHeader.h" +#include //============================================================================== diff --git a/extras/NetworkGraphicsDemo/Builds/Android/app/CMakeLists.txt b/extras/NetworkGraphicsDemo/Builds/Android/app/CMakeLists.txt index 6da7075a..0b74a58e 100644 --- a/extras/NetworkGraphicsDemo/Builds/Android/app/CMakeLists.txt +++ b/extras/NetworkGraphicsDemo/Builds/Android/app/CMakeLists.txt @@ -572,8 +572,6 @@ add_library( ${BINARY_NAME} "../../../../../modules/juce_core/misc/juce_Result.h" "../../../../../modules/juce_core/misc/juce_RuntimePermissions.cpp" "../../../../../modules/juce_core/misc/juce_RuntimePermissions.h" - "../../../../../modules/juce_core/misc/juce_StdFunctionCompat.cpp" - "../../../../../modules/juce_core/misc/juce_StdFunctionCompat.h" "../../../../../modules/juce_core/misc/juce_Uuid.cpp" "../../../../../modules/juce_core/misc/juce_Uuid.h" "../../../../../modules/juce_core/misc/juce_WindowsRegistry.h" @@ -689,6 +687,7 @@ add_library( ${BINARY_NAME} "../../../../../modules/juce_core/threads/juce_ThreadPool.h" "../../../../../modules/juce_core/threads/juce_TimeSliceThread.cpp" "../../../../../modules/juce_core/threads/juce_TimeSliceThread.h" + "../../../../../modules/juce_core/threads/juce_WaitableEvent.cpp" "../../../../../modules/juce_core/threads/juce_WaitableEvent.h" "../../../../../modules/juce_core/time/juce_PerformanceCounter.cpp" "../../../../../modules/juce_core/time/juce_PerformanceCounter.h" @@ -1937,8 +1936,6 @@ set_source_files_properties("../../../../../modules/juce_core/misc/juce_Result.c set_source_files_properties("../../../../../modules/juce_core/misc/juce_Result.h" PROPERTIES HEADER_FILE_ONLY TRUE) set_source_files_properties("../../../../../modules/juce_core/misc/juce_RuntimePermissions.cpp" PROPERTIES HEADER_FILE_ONLY TRUE) set_source_files_properties("../../../../../modules/juce_core/misc/juce_RuntimePermissions.h" PROPERTIES HEADER_FILE_ONLY TRUE) -set_source_files_properties("../../../../../modules/juce_core/misc/juce_StdFunctionCompat.cpp" PROPERTIES HEADER_FILE_ONLY TRUE) -set_source_files_properties("../../../../../modules/juce_core/misc/juce_StdFunctionCompat.h" PROPERTIES HEADER_FILE_ONLY TRUE) set_source_files_properties("../../../../../modules/juce_core/misc/juce_Uuid.cpp" PROPERTIES HEADER_FILE_ONLY TRUE) set_source_files_properties("../../../../../modules/juce_core/misc/juce_Uuid.h" PROPERTIES HEADER_FILE_ONLY TRUE) set_source_files_properties("../../../../../modules/juce_core/misc/juce_WindowsRegistry.h" PROPERTIES HEADER_FILE_ONLY TRUE) @@ -2054,6 +2051,7 @@ set_source_files_properties("../../../../../modules/juce_core/threads/juce_Threa set_source_files_properties("../../../../../modules/juce_core/threads/juce_ThreadPool.h" PROPERTIES HEADER_FILE_ONLY TRUE) set_source_files_properties("../../../../../modules/juce_core/threads/juce_TimeSliceThread.cpp" PROPERTIES HEADER_FILE_ONLY TRUE) set_source_files_properties("../../../../../modules/juce_core/threads/juce_TimeSliceThread.h" PROPERTIES HEADER_FILE_ONLY TRUE) +set_source_files_properties("../../../../../modules/juce_core/threads/juce_WaitableEvent.cpp" PROPERTIES HEADER_FILE_ONLY TRUE) set_source_files_properties("../../../../../modules/juce_core/threads/juce_WaitableEvent.h" PROPERTIES HEADER_FILE_ONLY TRUE) set_source_files_properties("../../../../../modules/juce_core/time/juce_PerformanceCounter.cpp" PROPERTIES HEADER_FILE_ONLY TRUE) set_source_files_properties("../../../../../modules/juce_core/time/juce_PerformanceCounter.h" PROPERTIES HEADER_FILE_ONLY TRUE) diff --git a/extras/NetworkGraphicsDemo/Builds/Android/app/src/main/AndroidManifest.xml b/extras/NetworkGraphicsDemo/Builds/Android/app/src/main/AndroidManifest.xml index 87a55c1e..d3befd5e 100644 --- a/extras/NetworkGraphicsDemo/Builds/Android/app/src/main/AndroidManifest.xml +++ b/extras/NetworkGraphicsDemo/Builds/Android/app/src/main/AndroidManifest.xml @@ -8,6 +8,7 @@ + diff --git a/extras/NetworkGraphicsDemo/Builds/Android/build.gradle b/extras/NetworkGraphicsDemo/Builds/Android/build.gradle index 2df9a8e7..cfd3a2f8 100644 --- a/extras/NetworkGraphicsDemo/Builds/Android/build.gradle +++ b/extras/NetworkGraphicsDemo/Builds/Android/build.gradle @@ -4,7 +4,7 @@ buildscript { jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:3.2.1' + classpath 'com.android.tools.build:gradle:3.5.3' } } diff --git a/extras/NetworkGraphicsDemo/Builds/Android/gradle/wrapper/gradle-wrapper.properties b/extras/NetworkGraphicsDemo/Builds/Android/gradle/wrapper/gradle-wrapper.properties index b460908d..b66802c7 100644 --- a/extras/NetworkGraphicsDemo/Builds/Android/gradle/wrapper/gradle-wrapper.properties +++ b/extras/NetworkGraphicsDemo/Builds/Android/gradle/wrapper/gradle-wrapper.properties @@ -1 +1 @@ -distributionUrl=https\://services.gradle.org/distributions/gradle-4.10-all.zip \ No newline at end of file +distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip \ No newline at end of file diff --git a/extras/NetworkGraphicsDemo/Builds/MacOSX/App.entitlements b/extras/NetworkGraphicsDemo/Builds/MacOSX/App.entitlements new file mode 100644 index 00000000..6631ffa6 --- /dev/null +++ b/extras/NetworkGraphicsDemo/Builds/MacOSX/App.entitlements @@ -0,0 +1,6 @@ + + + + + + diff --git a/extras/NetworkGraphicsDemo/Builds/MacOSX/NetworkGraphicsDemo.entitlements b/extras/NetworkGraphicsDemo/Builds/MacOSX/NetworkGraphicsDemo.entitlements deleted file mode 100644 index 6631ffa6..00000000 --- a/extras/NetworkGraphicsDemo/Builds/MacOSX/NetworkGraphicsDemo.entitlements +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/extras/NetworkGraphicsDemo/Builds/MacOSX/NetworkGraphicsDemo.xcodeproj/project.pbxproj b/extras/NetworkGraphicsDemo/Builds/MacOSX/NetworkGraphicsDemo.xcodeproj/project.pbxproj index 8d4427ba..2a3a20b3 100644 --- a/extras/NetworkGraphicsDemo/Builds/MacOSX/NetworkGraphicsDemo.xcodeproj/project.pbxproj +++ b/extras/NetworkGraphicsDemo/Builds/MacOSX/NetworkGraphicsDemo.xcodeproj/project.pbxproj @@ -171,13 +171,6 @@ path = ../../Source/SharedCanvas.h; sourceTree = "SOURCE_ROOT"; }; - 280A781618BDE3AF9BE15495 = { - isa = PBXFileReference; - lastKnownFileType = text.plist.xml; - name = NetworkGraphicsDemo.entitlements; - path = NetworkGraphicsDemo.entitlements; - sourceTree = "SOURCE_ROOT"; - }; 2E13A899F4E3C99054A3656F = { isa = PBXFileReference; lastKnownFileType = wrapper.framework; @@ -761,6 +754,7 @@ GCC_WARN_UNUSED_VARIABLE = YES; ONLY_ACTIVE_ARCH = YES; PRODUCT_NAME = "JUCE Network Graphics Demo"; + SDKROOT = macosx; WARNING_CFLAGS = "-Wreorder"; ZERO_LINK = NO; }; @@ -806,6 +800,7 @@ GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; PRODUCT_NAME = "JUCE Network Graphics Demo"; + SDKROOT = macosx; WARNING_CFLAGS = "-Wreorder"; ZERO_LINK = NO; }; diff --git a/extras/NetworkGraphicsDemo/Builds/VisualStudio2019/NetworkGraphicsDemo_App.vcxproj b/extras/NetworkGraphicsDemo/Builds/VisualStudio2019/NetworkGraphicsDemo_App.vcxproj index 69815331..99d26bb3 100644 --- a/extras/NetworkGraphicsDemo/Builds/VisualStudio2019/NetworkGraphicsDemo_App.vcxproj +++ b/extras/NetworkGraphicsDemo/Builds/VisualStudio2019/NetworkGraphicsDemo_App.vcxproj @@ -751,9 +751,6 @@ true - - true - true @@ -904,6 +901,9 @@ true + + true + true @@ -2250,7 +2250,6 @@ - diff --git a/extras/NetworkGraphicsDemo/Builds/VisualStudio2019/NetworkGraphicsDemo_App.vcxproj.filters b/extras/NetworkGraphicsDemo/Builds/VisualStudio2019/NetworkGraphicsDemo_App.vcxproj.filters index aa2ae0b1..0181b46d 100644 --- a/extras/NetworkGraphicsDemo/Builds/VisualStudio2019/NetworkGraphicsDemo_App.vcxproj.filters +++ b/extras/NetworkGraphicsDemo/Builds/VisualStudio2019/NetworkGraphicsDemo_App.vcxproj.filters @@ -1063,9 +1063,6 @@ JUCE Modules\juce_core\misc - - JUCE Modules\juce_core\misc - JUCE Modules\juce_core\misc @@ -1231,6 +1228,9 @@ JUCE Modules\juce_core\threads + + JUCE Modules\juce_core\threads + JUCE Modules\juce_core\time @@ -3309,9 +3309,6 @@ JUCE Modules\juce_core\misc - - JUCE Modules\juce_core\misc - JUCE Modules\juce_core\misc diff --git a/extras/NetworkGraphicsDemo/Builds/iOS/App.entitlements b/extras/NetworkGraphicsDemo/Builds/iOS/App.entitlements new file mode 100644 index 00000000..6631ffa6 --- /dev/null +++ b/extras/NetworkGraphicsDemo/Builds/iOS/App.entitlements @@ -0,0 +1,6 @@ + + + + + + diff --git a/extras/NetworkGraphicsDemo/Builds/iOS/NetworkGraphicsDemo.entitlements b/extras/NetworkGraphicsDemo/Builds/iOS/NetworkGraphicsDemo.entitlements deleted file mode 100644 index 6631ffa6..00000000 --- a/extras/NetworkGraphicsDemo/Builds/iOS/NetworkGraphicsDemo.entitlements +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/extras/NetworkGraphicsDemo/Builds/iOS/NetworkGraphicsDemo.xcodeproj/project.pbxproj b/extras/NetworkGraphicsDemo/Builds/iOS/NetworkGraphicsDemo.xcodeproj/project.pbxproj index 00987e47..69eb6184 100644 --- a/extras/NetworkGraphicsDemo/Builds/iOS/NetworkGraphicsDemo.xcodeproj/project.pbxproj +++ b/extras/NetworkGraphicsDemo/Builds/iOS/NetworkGraphicsDemo.xcodeproj/project.pbxproj @@ -190,13 +190,6 @@ path = ../../Source/SharedCanvas.h; sourceTree = "SOURCE_ROOT"; }; - 280A781618BDE3AF9BE15495 = { - isa = PBXFileReference; - lastKnownFileType = text.plist.xml; - name = NetworkGraphicsDemo.entitlements; - path = NetworkGraphicsDemo.entitlements; - sourceTree = "SOURCE_ROOT"; - }; 2E13A899F4E3C99054A3656F = { isa = PBXFileReference; lastKnownFileType = wrapper.framework; diff --git a/extras/NetworkGraphicsDemo/JuceLibraryCode/AppConfig.h b/extras/NetworkGraphicsDemo/JuceLibraryCode/AppConfig.h index f0cdeab2..a5889ec1 100644 --- a/extras/NetworkGraphicsDemo/JuceLibraryCode/AppConfig.h +++ b/extras/NetworkGraphicsDemo/JuceLibraryCode/AppConfig.h @@ -47,7 +47,7 @@ #define JUCE_USE_DARK_SPLASH_SCREEN 1 -#define JUCE_PROJUCER_VERSION 0x50405 +#define JUCE_PROJUCER_VERSION 0x50406 //============================================================================== #define JUCE_MODULE_AVAILABLE_juce_audio_basics 1 @@ -213,8 +213,8 @@ //============================================================================== // juce_events flags: -#ifndef JUCE_EXECUTE_APP_SUSPEND_ON_IOS_BACKGROUND_TASK - //#define JUCE_EXECUTE_APP_SUSPEND_ON_IOS_BACKGROUND_TASK 0 +#ifndef JUCE_EXECUTE_APP_SUSPEND_ON_BACKGROUND_TASK + //#define JUCE_EXECUTE_APP_SUSPEND_ON_BACKGROUND_TASK 0 #endif //============================================================================== diff --git a/extras/NetworkGraphicsDemo/NetworkGraphicsDemo.jucer b/extras/NetworkGraphicsDemo/NetworkGraphicsDemo.jucer index 79a87de7..319f8865 100644 --- a/extras/NetworkGraphicsDemo/NetworkGraphicsDemo.jucer +++ b/extras/NetworkGraphicsDemo/NetworkGraphicsDemo.jucer @@ -1,7 +1,7 @@ diff --git a/extras/NetworkGraphicsDemo/Source/Main.cpp b/extras/NetworkGraphicsDemo/Source/Main.cpp index 40c0597b..07298d41 100644 --- a/extras/NetworkGraphicsDemo/Source/Main.cpp +++ b/extras/NetworkGraphicsDemo/Source/Main.cpp @@ -24,7 +24,7 @@ ============================================================================== */ -#include "../JuceLibraryCode/JuceHeader.h" +#include namespace { diff --git a/extras/Projucer/Builds/LinuxMakefile/Makefile b/extras/Projucer/Builds/LinuxMakefile/Makefile index 25b49046..b98883b3 100644 --- a/extras/Projucer/Builds/LinuxMakefile/Makefile +++ b/extras/Projucer/Builds/LinuxMakefile/Makefile @@ -35,7 +35,7 @@ ifeq ($(CONFIG),Debug) TARGET_ARCH := -march=native endif - JUCE_CPPFLAGS := $(DEPFLAGS) -DLINUX=1 -DDEBUG=1 -D_DEBUG=1 -DJUCER_LINUX_MAKE_6D53C8B4=1 -DJUCE_APP_VERSION=5.4.5 -DJUCE_APP_VERSION_HEX=0x50405 $(shell pkg-config --cflags x11 xinerama xext freetype2 webkit2gtk-4.0 gtk+-x11-3.0) -pthread -I../../JuceLibraryCode -I../../../../modules $(CPPFLAGS) + JUCE_CPPFLAGS := $(DEPFLAGS) -DLINUX=1 -DDEBUG=1 -D_DEBUG=1 -DJUCER_LINUX_MAKE_6D53C8B4=1 -DJUCE_APP_VERSION=5.4.6 -DJUCE_APP_VERSION_HEX=0x50406 $(shell pkg-config --cflags x11 xinerama xext freetype2 webkit2gtk-4.0 gtk+-x11-3.0) -pthread -I../../JuceLibraryCode -I../../../../modules $(CPPFLAGS) JUCE_CPPFLAGS_APP := -DJucePlugin_Build_VST=0 -DJucePlugin_Build_VST3=0 -DJucePlugin_Build_AU=0 -DJucePlugin_Build_AUv3=0 -DJucePlugin_Build_RTAS=0 -DJucePlugin_Build_AAX=0 -DJucePlugin_Build_Standalone=0 -DJucePlugin_Build_Unity=0 JUCE_TARGET_APP := Projucer @@ -56,7 +56,7 @@ ifeq ($(CONFIG),Release) TARGET_ARCH := -march=native endif - JUCE_CPPFLAGS := $(DEPFLAGS) -DLINUX=1 -DNDEBUG=1 -DJUCER_LINUX_MAKE_6D53C8B4=1 -DJUCE_APP_VERSION=5.4.5 -DJUCE_APP_VERSION_HEX=0x50405 $(shell pkg-config --cflags x11 xinerama xext freetype2 webkit2gtk-4.0 gtk+-x11-3.0) -pthread -I../../JuceLibraryCode -I../../../../modules $(CPPFLAGS) + JUCE_CPPFLAGS := $(DEPFLAGS) -DLINUX=1 -DNDEBUG=1 -DJUCER_LINUX_MAKE_6D53C8B4=1 -DJUCE_APP_VERSION=5.4.6 -DJUCE_APP_VERSION_HEX=0x50406 $(shell pkg-config --cflags x11 xinerama xext freetype2 webkit2gtk-4.0 gtk+-x11-3.0) -pthread -I../../JuceLibraryCode -I../../../../modules $(CPPFLAGS) JUCE_CPPFLAGS_APP := -DJucePlugin_Build_VST=0 -DJucePlugin_Build_VST3=0 -DJucePlugin_Build_AU=0 -DJucePlugin_Build_AUv3=0 -DJucePlugin_Build_RTAS=0 -DJucePlugin_Build_AAX=0 -DJucePlugin_Build_Standalone=0 -DJucePlugin_Build_Unity=0 JUCE_TARGET_APP := Projucer @@ -113,6 +113,7 @@ OBJECTS_APP := \ $(JUCE_OBJDIR)/jucer_CodeHelpers_1e797672.o \ $(JUCE_OBJDIR)/jucer_FileHelpers_54f12f83.o \ $(JUCE_OBJDIR)/jucer_MiscUtilities_31fc8dd8.o \ + $(JUCE_OBJDIR)/jucer_VersionInfo_46f3ed40.o \ $(JUCE_OBJDIR)/jucer_PIPGenerator_fd3402c7.o \ $(JUCE_OBJDIR)/jucer_Icons_d02d18f1.o \ $(JUCE_OBJDIR)/jucer_JucerTreeViewBase_9b9f2ff0.o \ @@ -368,6 +369,11 @@ $(JUCE_OBJDIR)/jucer_MiscUtilities_31fc8dd8.o: ../../Source/Utility/Helpers/juce @echo "Compiling jucer_MiscUtilities.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" +$(JUCE_OBJDIR)/jucer_VersionInfo_46f3ed40.o: ../../Source/Utility/Helpers/jucer_VersionInfo.cpp + -$(V_AT)mkdir -p $(JUCE_OBJDIR) + @echo "Compiling jucer_VersionInfo.cpp" + $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" + $(JUCE_OBJDIR)/jucer_PIPGenerator_fd3402c7.o: ../../Source/Utility/PIPs/jucer_PIPGenerator.cpp -$(V_AT)mkdir -p $(JUCE_OBJDIR) @echo "Compiling jucer_PIPGenerator.cpp" diff --git a/extras/Projucer/Builds/MacOSX/App.entitlements b/extras/Projucer/Builds/MacOSX/App.entitlements new file mode 100644 index 00000000..6631ffa6 --- /dev/null +++ b/extras/Projucer/Builds/MacOSX/App.entitlements @@ -0,0 +1,6 @@ + + + + + + diff --git a/extras/Projucer/Builds/MacOSX/Info-App.plist b/extras/Projucer/Builds/MacOSX/Info-App.plist index c2214834..6ea5928a 100644 --- a/extras/Projucer/Builds/MacOSX/Info-App.plist +++ b/extras/Projucer/Builds/MacOSX/Info-App.plist @@ -37,9 +37,9 @@ CFBundleSignature ???? CFBundleShortVersionString - 5.4.5 + 5.4.6 CFBundleVersion - 5.4.5 + 5.4.6 NSHumanReadableCopyright ROLI Ltd. NSHighResolutionCapable diff --git a/extras/Projucer/Builds/MacOSX/Projucer.entitlements b/extras/Projucer/Builds/MacOSX/Projucer.entitlements deleted file mode 100644 index 6631ffa6..00000000 --- a/extras/Projucer/Builds/MacOSX/Projucer.entitlements +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/extras/Projucer/Builds/MacOSX/Projucer.xcodeproj/project.pbxproj b/extras/Projucer/Builds/MacOSX/Projucer.xcodeproj/project.pbxproj index 6db9d905..3990ab68 100644 --- a/extras/Projucer/Builds/MacOSX/Projucer.xcodeproj/project.pbxproj +++ b/extras/Projucer/Builds/MacOSX/Projucer.xcodeproj/project.pbxproj @@ -9,6 +9,10 @@ isa = PBXBuildFile; fileRef = 09DE066936CF037E9709ADB1; }; + 8B4A593B3869815BBAC3EF93 = { + isa = PBXBuildFile; + fileRef = 7B3F7ECF6DBF8C8EE5C2CB86; + }; A578EAD4BB55680E8097BE0F = { isa = PBXBuildFile; fileRef = 80D62B907248523E6943298B; @@ -17,10 +21,6 @@ isa = PBXBuildFile; fileRef = 5A75806B34E4EA6598A6024A; }; - 8B4A593B3869815BBAC3EF93 = { - isa = PBXBuildFile; - fileRef = 7B3F7ECF6DBF8C8EE5C2CB86; - }; A14C2C2725DA3CA7995D2815 = { isa = PBXBuildFile; fileRef = 210CD22F25F2C22F9CEEB025; @@ -257,6 +257,10 @@ isa = PBXBuildFile; fileRef = 486E8D02DAD2A0BF54A901C0; }; + 44AD0D81A65C5EAE3BE588FD = { + isa = PBXBuildFile; + fileRef = FF3A6A384D536E1AEF47CD54; + }; 638C7247B6DBA67EFE46E124 = { isa = PBXBuildFile; fileRef = 191330B20DAC08B890656EA0; @@ -1973,13 +1977,6 @@ path = "../../../../modules/juce_graphics"; sourceTree = "SOURCE_ROOT"; }; - B7017BD3427B46FBAAAE448A = { - isa = PBXFileReference; - lastKnownFileType = text.plist.xml; - name = Projucer.entitlements; - path = Projucer.entitlements; - sourceTree = "SOURCE_ROOT"; - }; B8385E9A644BD3CD94876448 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; @@ -2099,6 +2096,13 @@ path = "../../Source/Wizards/jucer_TemplateThumbnailsComponent.h"; sourceTree = "SOURCE_ROOT"; }; + C16F9F479A3A5F6DAD7647A2 = { + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = "jucer_VersionInfo.h"; + path = "../../Source/Utility/Helpers/jucer_VersionInfo.h"; + sourceTree = "SOURCE_ROOT"; + }; C187718F7B9EBA88584B43F3 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; @@ -2589,6 +2593,13 @@ path = "../../Source/Utility/UI/jucer_ProjucerLookAndFeel.h"; sourceTree = "SOURCE_ROOT"; }; + FF3A6A384D536E1AEF47CD54 = { + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + name = "jucer_VersionInfo.cpp"; + path = "../../Source/Utility/Helpers/jucer_VersionInfo.cpp"; + sourceTree = "SOURCE_ROOT"; + }; FF68231DE2B395461009116C = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; @@ -3018,6 +3029,8 @@ A6C4AE13FB409DE414094CFA, 6FD8DBC0FF42C87D8BEE2452, 00515BA4EC5A7D4DC078ED37, + FF3A6A384D536E1AEF47CD54, + C16F9F479A3A5F6DAD7647A2, ); name = Helpers; sourceTree = ""; @@ -3159,9 +3172,9 @@ 0FFEF043CA89142B18C79ABE = { isa = PBXGroup; children = ( + 7B3F7ECF6DBF8C8EE5C2CB86, 80D62B907248523E6943298B, 5A75806B34E4EA6598A6024A, - 7B3F7ECF6DBF8C8EE5C2CB86, 210CD22F25F2C22F9CEEB025, D00F311BFC3C2625C457CB9B, D1F9B0E9F5D54FE48BEB46EA, @@ -3215,8 +3228,8 @@ "_DEBUG=1", "DEBUG=1", "JUCER_XCODE_MAC_F6D2F4CF=1", - "JUCE_APP_VERSION=5.4.5", - "JUCE_APP_VERSION_HEX=0x50405", + "JUCE_APP_VERSION=5.4.6", + "JUCE_APP_VERSION_HEX=0x50406", "JucePlugin_Build_VST=0", "JucePlugin_Build_VST3=0", "JucePlugin_Build_AU=0", @@ -3259,8 +3272,8 @@ "_NDEBUG=1", "NDEBUG=1", "JUCER_XCODE_MAC_F6D2F4CF=1", - "JUCE_APP_VERSION=5.4.5", - "JUCE_APP_VERSION_HEX=0x50405", + "JUCE_APP_VERSION=5.4.6", + "JUCE_APP_VERSION_HEX=0x50406", "JucePlugin_Build_VST=0", "JucePlugin_Build_VST3=0", "JucePlugin_Build_AU=0", @@ -3330,6 +3343,7 @@ GCC_WARN_UNUSED_VARIABLE = YES; ONLY_ACTIVE_ARCH = YES; PRODUCT_NAME = "Projucer"; + SDKROOT = macosx; WARNING_CFLAGS = "-Wreorder"; ZERO_LINK = NO; }; @@ -3375,6 +3389,7 @@ GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; PRODUCT_NAME = "Projucer"; + SDKROOT = macosx; WARNING_CFLAGS = "-Wreorder"; ZERO_LINK = NO; }; @@ -3460,6 +3475,7 @@ 8BE478303CDF061B72F219E2, BF913199032B4CE970E82AA3, 25EF9B3FECB4C9F0F522DCAA, + 44AD0D81A65C5EAE3BE588FD, 638C7247B6DBA67EFE46E124, D0E26EB54B0087C8BE3D541E, 468548FB21D264DC12321327, @@ -3483,9 +3499,9 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 8B4A593B3869815BBAC3EF93, A578EAD4BB55680E8097BE0F, C1B9334AE849F93FB3C56B34, - 8B4A593B3869815BBAC3EF93, A14C2C2725DA3CA7995D2815, 1E76E36772355E2A43CF4961, 241F29FCBB7A17BB44A0B10C, diff --git a/extras/Projucer/Builds/VisualStudio2015/Projucer_App.vcxproj b/extras/Projucer/Builds/VisualStudio2015/Projucer_App.vcxproj index a025ed09..a72d7954 100644 --- a/extras/Projucer/Builds/VisualStudio2015/Projucer_App.vcxproj +++ b/extras/Projucer/Builds/VisualStudio2015/Projucer_App.vcxproj @@ -64,7 +64,7 @@ Disabled ProgramDatabase ..\..\JuceLibraryCode;..\..\..\..\modules;%(AdditionalIncludeDirectories) - _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;DEBUG;_DEBUG;JUCER_VS2015_78A5022=1;JUCE_APP_VERSION=5.4.5;JUCE_APP_VERSION_HEX=0x50405;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_RTAS=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;DEBUG;_DEBUG;JUCER_VS2015_78A5022=1;JUCE_APP_VERSION=5.4.6;JUCE_APP_VERSION_HEX=0x50406;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_RTAS=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;%(PreprocessorDefinitions) MultiThreadedDebugDLL true @@ -106,7 +106,7 @@ Full ..\..\JuceLibraryCode;..\..\..\..\modules;%(AdditionalIncludeDirectories) - _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;JUCER_VS2015_78A5022=1;JUCE_APP_VERSION=5.4.5;JUCE_APP_VERSION_HEX=0x50405;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_RTAS=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;JUCER_VS2015_78A5022=1;JUCE_APP_VERSION=5.4.6;JUCE_APP_VERSION_HEX=0x50406;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_RTAS=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;%(PreprocessorDefinitions) MultiThreaded true @@ -233,6 +233,7 @@ + @@ -339,9 +340,6 @@ true - - true - true @@ -492,6 +490,9 @@ true + + true + true @@ -1621,6 +1622,7 @@ + @@ -1706,7 +1708,6 @@ - diff --git a/extras/Projucer/Builds/VisualStudio2015/Projucer_App.vcxproj.filters b/extras/Projucer/Builds/VisualStudio2015/Projucer_App.vcxproj.filters index 7bc5135c..16e2c05d 100644 --- a/extras/Projucer/Builds/VisualStudio2015/Projucer_App.vcxproj.filters +++ b/extras/Projucer/Builds/VisualStudio2015/Projucer_App.vcxproj.filters @@ -496,6 +496,9 @@ Projucer\Utility\Helpers + + Projucer\Utility\Helpers + Projucer\Utility\PIPs @@ -616,9 +619,6 @@ JUCE Modules\juce_core\misc - - JUCE Modules\juce_core\misc - JUCE Modules\juce_core\misc @@ -784,6 +784,9 @@ JUCE Modules\juce_core\threads + + JUCE Modules\juce_core\threads + JUCE Modules\juce_core\time @@ -2322,6 +2325,9 @@ Projucer\Utility\Helpers + + Projucer\Utility\Helpers + Projucer\Utility\PIPs @@ -2577,9 +2583,6 @@ JUCE Modules\juce_core\misc - - JUCE Modules\juce_core\misc - JUCE Modules\juce_core\misc diff --git a/extras/Projucer/Builds/VisualStudio2015/resources.rc b/extras/Projucer/Builds/VisualStudio2015/resources.rc index c4143235..0dfcbc7f 100644 --- a/extras/Projucer/Builds/VisualStudio2015/resources.rc +++ b/extras/Projucer/Builds/VisualStudio2015/resources.rc @@ -7,7 +7,7 @@ #include VS_VERSION_INFO VERSIONINFO -FILEVERSION 5,4,5,0 +FILEVERSION 5,4,6,0 BEGIN BLOCK "StringFileInfo" BEGIN @@ -16,9 +16,9 @@ BEGIN VALUE "CompanyName", "ROLI Ltd.\0" VALUE "LegalCopyright", "ROLI Ltd.\0" VALUE "FileDescription", "Projucer\0" - VALUE "FileVersion", "5.4.5\0" + VALUE "FileVersion", "5.4.6\0" VALUE "ProductName", "Projucer\0" - VALUE "ProductVersion", "5.4.5\0" + VALUE "ProductVersion", "5.4.6\0" END END diff --git a/extras/Projucer/Builds/VisualStudio2017/Projucer_App.vcxproj b/extras/Projucer/Builds/VisualStudio2017/Projucer_App.vcxproj index 7c8751a7..0bc14790 100644 --- a/extras/Projucer/Builds/VisualStudio2017/Projucer_App.vcxproj +++ b/extras/Projucer/Builds/VisualStudio2017/Projucer_App.vcxproj @@ -64,7 +64,7 @@ Disabled ProgramDatabase ..\..\JuceLibraryCode;..\..\..\..\modules;%(AdditionalIncludeDirectories) - _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;DEBUG;_DEBUG;JUCER_VS2017_78A5024=1;JUCE_APP_VERSION=5.4.5;JUCE_APP_VERSION_HEX=0x50405;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_RTAS=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;DEBUG;_DEBUG;JUCER_VS2017_78A5024=1;JUCE_APP_VERSION=5.4.6;JUCE_APP_VERSION_HEX=0x50406;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_RTAS=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;%(PreprocessorDefinitions) MultiThreadedDebug true @@ -106,7 +106,7 @@ Full ..\..\JuceLibraryCode;..\..\..\..\modules;%(AdditionalIncludeDirectories) - _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;JUCER_VS2017_78A5024=1;JUCE_APP_VERSION=5.4.5;JUCE_APP_VERSION_HEX=0x50405;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_RTAS=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;JUCER_VS2017_78A5024=1;JUCE_APP_VERSION=5.4.6;JUCE_APP_VERSION_HEX=0x50406;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_RTAS=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;%(PreprocessorDefinitions) MultiThreaded true @@ -233,6 +233,7 @@ + @@ -339,9 +340,6 @@ true - - true - true @@ -492,6 +490,9 @@ true + + true + true @@ -1621,6 +1622,7 @@ + @@ -1706,7 +1708,6 @@ - diff --git a/extras/Projucer/Builds/VisualStudio2017/Projucer_App.vcxproj.filters b/extras/Projucer/Builds/VisualStudio2017/Projucer_App.vcxproj.filters index a2ec767b..8148e932 100644 --- a/extras/Projucer/Builds/VisualStudio2017/Projucer_App.vcxproj.filters +++ b/extras/Projucer/Builds/VisualStudio2017/Projucer_App.vcxproj.filters @@ -496,6 +496,9 @@ Projucer\Utility\Helpers + + Projucer\Utility\Helpers + Projucer\Utility\PIPs @@ -616,9 +619,6 @@ JUCE Modules\juce_core\misc - - JUCE Modules\juce_core\misc - JUCE Modules\juce_core\misc @@ -784,6 +784,9 @@ JUCE Modules\juce_core\threads + + JUCE Modules\juce_core\threads + JUCE Modules\juce_core\time @@ -2322,6 +2325,9 @@ Projucer\Utility\Helpers + + Projucer\Utility\Helpers + Projucer\Utility\PIPs @@ -2577,9 +2583,6 @@ JUCE Modules\juce_core\misc - - JUCE Modules\juce_core\misc - JUCE Modules\juce_core\misc diff --git a/extras/Projucer/Builds/VisualStudio2017/resources.rc b/extras/Projucer/Builds/VisualStudio2017/resources.rc index c4143235..0dfcbc7f 100644 --- a/extras/Projucer/Builds/VisualStudio2017/resources.rc +++ b/extras/Projucer/Builds/VisualStudio2017/resources.rc @@ -7,7 +7,7 @@ #include VS_VERSION_INFO VERSIONINFO -FILEVERSION 5,4,5,0 +FILEVERSION 5,4,6,0 BEGIN BLOCK "StringFileInfo" BEGIN @@ -16,9 +16,9 @@ BEGIN VALUE "CompanyName", "ROLI Ltd.\0" VALUE "LegalCopyright", "ROLI Ltd.\0" VALUE "FileDescription", "Projucer\0" - VALUE "FileVersion", "5.4.5\0" + VALUE "FileVersion", "5.4.6\0" VALUE "ProductName", "Projucer\0" - VALUE "ProductVersion", "5.4.5\0" + VALUE "ProductVersion", "5.4.6\0" END END diff --git a/extras/Projucer/Builds/VisualStudio2019/Projucer_App.vcxproj b/extras/Projucer/Builds/VisualStudio2019/Projucer_App.vcxproj index 0a28052e..dc49d519 100644 --- a/extras/Projucer/Builds/VisualStudio2019/Projucer_App.vcxproj +++ b/extras/Projucer/Builds/VisualStudio2019/Projucer_App.vcxproj @@ -64,7 +64,7 @@ Disabled ProgramDatabase ..\..\JuceLibraryCode;..\..\..\..\modules;%(AdditionalIncludeDirectories) - _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;DEBUG;_DEBUG;JUCER_VS2019_78A5026=1;JUCE_APP_VERSION=5.4.5;JUCE_APP_VERSION_HEX=0x50405;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_RTAS=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;DEBUG;_DEBUG;JUCER_VS2019_78A5026=1;JUCE_APP_VERSION=5.4.6;JUCE_APP_VERSION_HEX=0x50406;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_RTAS=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;%(PreprocessorDefinitions) MultiThreadedDebug true @@ -106,7 +106,7 @@ Full ..\..\JuceLibraryCode;..\..\..\..\modules;%(AdditionalIncludeDirectories) - _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;JUCER_VS2019_78A5026=1;JUCE_APP_VERSION=5.4.5;JUCE_APP_VERSION_HEX=0x50405;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_RTAS=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;JUCER_VS2019_78A5026=1;JUCE_APP_VERSION=5.4.6;JUCE_APP_VERSION_HEX=0x50406;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_RTAS=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;%(PreprocessorDefinitions) MultiThreaded true @@ -233,6 +233,7 @@ + @@ -339,9 +340,6 @@ true - - true - true @@ -492,6 +490,9 @@ true + + true + true @@ -1621,6 +1622,7 @@ + @@ -1706,7 +1708,6 @@ - diff --git a/extras/Projucer/Builds/VisualStudio2019/Projucer_App.vcxproj.filters b/extras/Projucer/Builds/VisualStudio2019/Projucer_App.vcxproj.filters index 754d0ff9..1acc5e80 100644 --- a/extras/Projucer/Builds/VisualStudio2019/Projucer_App.vcxproj.filters +++ b/extras/Projucer/Builds/VisualStudio2019/Projucer_App.vcxproj.filters @@ -496,6 +496,9 @@ Projucer\Utility\Helpers + + Projucer\Utility\Helpers + Projucer\Utility\PIPs @@ -616,9 +619,6 @@ JUCE Modules\juce_core\misc - - JUCE Modules\juce_core\misc - JUCE Modules\juce_core\misc @@ -784,6 +784,9 @@ JUCE Modules\juce_core\threads + + JUCE Modules\juce_core\threads + JUCE Modules\juce_core\time @@ -2322,6 +2325,9 @@ Projucer\Utility\Helpers + + Projucer\Utility\Helpers + Projucer\Utility\PIPs @@ -2577,9 +2583,6 @@ JUCE Modules\juce_core\misc - - JUCE Modules\juce_core\misc - JUCE Modules\juce_core\misc diff --git a/extras/Projucer/Builds/VisualStudio2019/resources.rc b/extras/Projucer/Builds/VisualStudio2019/resources.rc index c4143235..0dfcbc7f 100644 --- a/extras/Projucer/Builds/VisualStudio2019/resources.rc +++ b/extras/Projucer/Builds/VisualStudio2019/resources.rc @@ -7,7 +7,7 @@ #include VS_VERSION_INFO VERSIONINFO -FILEVERSION 5,4,5,0 +FILEVERSION 5,4,6,0 BEGIN BLOCK "StringFileInfo" BEGIN @@ -16,9 +16,9 @@ BEGIN VALUE "CompanyName", "ROLI Ltd.\0" VALUE "LegalCopyright", "ROLI Ltd.\0" VALUE "FileDescription", "Projucer\0" - VALUE "FileVersion", "5.4.5\0" + VALUE "FileVersion", "5.4.6\0" VALUE "ProductName", "Projucer\0" - VALUE "ProductVersion", "5.4.5\0" + VALUE "ProductVersion", "5.4.6\0" END END diff --git a/extras/Projucer/JuceLibraryCode/AppConfig.h b/extras/Projucer/JuceLibraryCode/AppConfig.h index dffd5af7..e9598ed9 100644 --- a/extras/Projucer/JuceLibraryCode/AppConfig.h +++ b/extras/Projucer/JuceLibraryCode/AppConfig.h @@ -66,7 +66,7 @@ #define JUCE_USE_DARK_SPLASH_SCREEN 1 -#define JUCE_PROJUCER_VERSION 0x50405 +#define JUCE_PROJUCER_VERSION 0x50406 //============================================================================== #define JUCE_MODULE_AVAILABLE_juce_analytics 1 @@ -126,8 +126,8 @@ //============================================================================== // juce_events flags: -#ifndef JUCE_EXECUTE_APP_SUSPEND_ON_IOS_BACKGROUND_TASK - //#define JUCE_EXECUTE_APP_SUSPEND_ON_IOS_BACKGROUND_TASK 0 +#ifndef JUCE_EXECUTE_APP_SUSPEND_ON_BACKGROUND_TASK + //#define JUCE_EXECUTE_APP_SUSPEND_ON_BACKGROUND_TASK 0 #endif //============================================================================== diff --git a/extras/Projucer/JuceLibraryCode/BinaryData.cpp b/extras/Projucer/JuceLibraryCode/BinaryData.cpp index 3e796feb..096299a5 100644 --- a/extras/Projucer/JuceLibraryCode/BinaryData.cpp +++ b/extras/Projucer/JuceLibraryCode/BinaryData.cpp @@ -6174,7 +6174,7 @@ static const unsigned char temp_binary_data_35[] = "#pragma once\r\n" "\r\n" "//[Headers] -- You can add your own extra header files here --\r\n" -"%%include_juce_header%%\r\n" +"%%include_juce%%\r\n" "//[/Headers]\r\n" "\r\n" "%%include_files_h%%\r\n" @@ -6192,7 +6192,7 @@ static const unsigned char temp_binary_data_35[] = "public:\r\n" " //==============================================================================\r\n" " %%class_name%% (%%constructor_params%%);\r\n" -" ~%%class_name%%();\r\n" +" ~%%class_name%%() override;\r\n" "\r\n" " //==============================================================================\r\n" " //[UserMethods] -- You can add your own custom methods in this section.\r\n" @@ -7204,7 +7204,7 @@ static const unsigned char temp_binary_data_53[] = " ==============================================================================\r\n" "*/\r\n" "\r\n" -"#include \"../JuceLibraryCode/JuceHeader.h\"\r\n" +"%%include_juce%%\r\n" "#include \"%%filename%%\"\r\n" "\r\n" "%%component_begin%%\r\n" @@ -7846,7 +7846,7 @@ const char* getNamedResource (const char* resourceNameUTF8, int& numBytes) case 0x51b49ac5: numBytes = 6036; return jucer_AudioPluginFilterTemplate_cpp; case 0x488afa0a: numBytes = 2272; return jucer_AudioPluginFilterTemplate_h; case 0xabad7041: numBytes = 2126; return jucer_ComponentTemplate_cpp; - case 0xfc72fe86: numBytes = 2042; return jucer_ComponentTemplate_h; + case 0xfc72fe86: numBytes = 2044; return jucer_ComponentTemplate_h; case 0x1657b643: numBytes = 1693; return jucer_ContentCompSimpleTemplate_h; case 0x0b66646c: numBytes = 1190; return jucer_ContentCompTemplate_cpp; case 0x6fa10171: numBytes = 1071; return jucer_ContentCompTemplate_h; @@ -7864,7 +7864,7 @@ const char* getNamedResource (const char* resourceNameUTF8, int& numBytes) case 0x7fbac252: numBytes = 1665; return jucer_OpenGLComponentTemplate_cpp; case 0x491fa0d7: numBytes = 1263; return jucer_OpenGLComponentTemplate_h; case 0xbc050edc: numBytes = 4926; return jucer_PIPAudioProcessorTemplate_h; - case 0xf4ca9e9a: numBytes = 2447; return jucer_PIPMain_cpp; + case 0xf4ca9e9a: numBytes = 2421; return jucer_PIPMain_cpp; case 0x0b16e320: numBytes = 517; return jucer_PIPTemplate_h; case 0xcd472557: numBytes = 6433; return jucer_UnityPluginGUIScript_cs; case 0x763d39dc: numBytes = 1050; return colourscheme_dark_xml; diff --git a/extras/Projucer/JuceLibraryCode/BinaryData.h b/extras/Projucer/JuceLibraryCode/BinaryData.h index 1f027de6..474d506e 100644 --- a/extras/Projucer/JuceLibraryCode/BinaryData.h +++ b/extras/Projucer/JuceLibraryCode/BinaryData.h @@ -114,7 +114,7 @@ namespace BinaryData const int jucer_ComponentTemplate_cppSize = 2126; extern const char* jucer_ComponentTemplate_h; - const int jucer_ComponentTemplate_hSize = 2042; + const int jucer_ComponentTemplate_hSize = 2044; extern const char* jucer_ContentCompSimpleTemplate_h; const int jucer_ContentCompSimpleTemplate_hSize = 1693; @@ -168,7 +168,7 @@ namespace BinaryData const int jucer_PIPAudioProcessorTemplate_hSize = 4926; extern const char* jucer_PIPMain_cpp; - const int jucer_PIPMain_cppSize = 2447; + const int jucer_PIPMain_cppSize = 2421; extern const char* jucer_PIPTemplate_h; const int jucer_PIPTemplate_hSize = 517; diff --git a/extras/Projucer/JuceLibraryCode/JuceHeader.h b/extras/Projucer/JuceLibraryCode/JuceHeader.h index 765b4265..acb1d2cf 100644 --- a/extras/Projucer/JuceLibraryCode/JuceHeader.h +++ b/extras/Projucer/JuceLibraryCode/JuceHeader.h @@ -45,7 +45,7 @@ namespace ProjectInfo { const char* const projectName = "Projucer"; const char* const companyName = "ROLI Ltd."; - const char* const versionString = "5.4.5"; - const int versionNumber = 0x50405; + const char* const versionString = "5.4.6"; + const int versionNumber = 0x50406; } #endif diff --git a/extras/Projucer/Projucer.jucer b/extras/Projucer/Projucer.jucer index 6f4f7080..0df45026 100644 --- a/extras/Projucer/Projucer.jucer +++ b/extras/Projucer/Projucer.jucer @@ -1,7 +1,7 @@ @@ -636,6 +636,10 @@ file="Source/Utility/Helpers/jucer_TranslationHelpers.h"/> + + showStartPage(); - mainWindowList.avoidSuperimposedWindows (mw); + mainWindowList.checkWindowBounds (*mw); } void ProjucerApplication::createNewProjectFromClipboard() diff --git a/extras/Projucer/Source/Application/jucer_AutoUpdater.cpp b/extras/Projucer/Source/Application/jucer_AutoUpdater.cpp index a54b5273..94e8eb72 100644 --- a/extras/Projucer/Source/Application/jucer_AutoUpdater.cpp +++ b/extras/Projucer/Source/Application/jucer_AutoUpdater.cpp @@ -52,119 +52,65 @@ void LatestVersionCheckerAndUpdater::checkForNewVersion (bool showAlerts) //============================================================================== void LatestVersionCheckerAndUpdater::run() { - queryUpdateServer(); + auto info = VersionInfo::fetchLatestFromUpdateServer(); - if (! threadShouldExit()) - MessageManager::callAsync ([this] { processResult(); }); -} - -//============================================================================== -String getOSString() -{ - #if JUCE_MAC - return "OSX"; - #elif JUCE_WINDOWS - return "Windows"; - #elif JUCE_LINUX - return "Linux"; - #else - jassertfalse; - return "Unknown"; - #endif -} - -namespace VersionHelpers -{ - String formatProductVersion (int versionNum) + if (info == nullptr) { - int major = (versionNum & 0xff0000) >> 16; - int minor = (versionNum & 0x00ff00) >> 8; - int build = (versionNum & 0x0000ff) >> 0; - - return String (major) + '.' + String (minor) + '.' + String (build); - } + if (showAlertWindows) + AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon, + "Update Server Communication Error", + "Failed to communicate with the JUCE update server.\n" + "Please try again in a few minutes.\n\n" + "If this problem persists you can download the latest version of JUCE from juce.com"); - String getProductVersionString() - { - return formatProductVersion (ProjectInfo::versionNumber); + return; } - bool isNewVersion (const String& current, const String& other) + if (! info->isNewerVersionThanCurrent()) { - auto currentTokens = StringArray::fromTokens (current, ".", {}); - auto otherTokens = StringArray::fromTokens (other, ".", {}); - - jassert (currentTokens.size() == 3 && otherTokens.size() == 3); - - if (currentTokens[0].getIntValue() == otherTokens[0].getIntValue()) - { - if (currentTokens[1].getIntValue() == otherTokens[1].getIntValue()) - return currentTokens[2].getIntValue() < otherTokens[2].getIntValue(); - - return currentTokens[1].getIntValue() < otherTokens[1].getIntValue(); - } - - return currentTokens[0].getIntValue() < otherTokens[0].getIntValue(); - } -} - -void LatestVersionCheckerAndUpdater::queryUpdateServer() -{ - StringPairArray responseHeaders; - - URL latestVersionURL ("https://my.roli.com/software_versions/update_to/Projucer/" - + VersionHelpers::getProductVersionString() + '/' + getOSString() - + "?language=" + SystemStats::getUserLanguage()); - - std::unique_ptr inStream (latestVersionURL.createInputStream (false, nullptr, nullptr, - "X-API-Key: 265441b-343403c-20f6932-76361d\nContent-Type: " - "application/json\nAccept: application/json; version=1", - 0, &responseHeaders, &statusCode, 0)); - - if (threadShouldExit()) + if (showAlertWindows) + AlertWindow::showMessageBoxAsync (AlertWindow::InfoIcon, + "No New Version Available", + "Your JUCE version is up to date."); return; - - if (inStream.get() != nullptr && (statusCode == 303 || statusCode == 400)) - { - if (statusCode == 303) - relativeDownloadPath = responseHeaders["Location"]; - - jassert (relativeDownloadPath.isNotEmpty()); - - jsonReply = JSON::parse (inStream->readEntireStreamAsString()); - } - else if (showAlertWindows) - { - if (statusCode == 204) - AlertWindow::showMessageBoxAsync (AlertWindow::InfoIcon, "No New Version Available", "Your JUCE version is up to date."); - else - AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon, "Network Error", "Could not connect to the web server.\n" - "Please check your internet connection and try again."); } -} - -void LatestVersionCheckerAndUpdater::processResult() -{ - if (! jsonReply.isObject()) - return; - if (statusCode == 400) + auto osString = [] { - auto errorObject = jsonReply.getDynamicObject()->getProperty ("error"); - - if (errorObject.isObject()) + #if JUCE_MAC + return "osx"; + #elif JUCE_WINDOWS + return "windows"; + #elif JUCE_LINUX + return "linux"; + #else + jassertfalse; + return "Unknown"; + #endif + }(); + + String requiredFilename ("juce-" + info->versionString + "-" + osString + ".zip"); + + for (auto& asset : info->assets) + { + if (asset.name == requiredFilename) { - auto message = errorObject.getProperty ("message", {}).toString(); + auto versionString = info->versionString; + auto releaseNotes = info->releaseNotes; - if (message.isNotEmpty()) - AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon, "JUCE Updater", message); + MessageManager::callAsync ([this, versionString, releaseNotes, asset] + { + askUserAboutNewVersion (versionString, releaseNotes, asset); + }); + + return; } } - else if (statusCode == 303) - { - askUserAboutNewVersion (jsonReply.getProperty ("version", {}).toString(), - jsonReply.getProperty ("notes", {}).toString()); - } + + if (showAlertWindows) + AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon, + "Failed to find any new downloads", + "Please try again in a few minutes."); } //============================================================================== @@ -246,14 +192,15 @@ public: RectanglePlacement::stretchToFit, 1.0f); } - static std::unique_ptr launchDialog (const String& newVersion, const String& releaseNotes) + static std::unique_ptr launchDialog (const String& newVersionString, + const String& releaseNotes) { DialogWindow::LaunchOptions options; - options.dialogTitle = "Download JUCE version " + newVersion + "?"; + options.dialogTitle = "Download JUCE version " + newVersionString + "?"; options.resizable = false; - auto* content = new UpdateDialog (newVersion, releaseNotes); + auto* content = new UpdateDialog (newVersionString, releaseNotes); options.content.set (content, true); std::unique_ptr dialog (options.create()); @@ -292,66 +239,83 @@ private: DialogWindow* parentWindow = nullptr; }; -void LatestVersionCheckerAndUpdater::askUserForLocationToDownload() +void LatestVersionCheckerAndUpdater::askUserForLocationToDownload (const VersionInfo::Asset& asset) { - FileChooser chooser ("Please select the location into which you'd like to install the new version", + FileChooser chooser ("Please select the location into which you would like to install the new version", { getAppSettings().getStoredPath (Ids::jucePath, TargetOS::getThisOS()).get() }); if (chooser.browseForDirectory()) { auto targetFolder = chooser.getResult(); - if (isJUCEFolder (targetFolder)) + // By default we will install into 'targetFolder/JUCE', but we should install into + // 'targetFolder' if that is an existing JUCE directory. + bool willOverwriteJuceFolder = [&targetFolder] + { + if (isJUCEFolder (targetFolder)) + return true; + + targetFolder = targetFolder.getChildFile ("JUCE"); + + return isJUCEFolder (targetFolder); + }(); + + auto targetFolderPath = targetFolder.getFullPathName(); + + if (willOverwriteJuceFolder) { if (targetFolder.getChildFile (".git").isDirectory()) { AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon, "Downloading New JUCE Version", - "This folder is a GIT repository!\n\nYou should use a \"git pull\" to update it to the latest version."); + targetFolderPath + "\n\nis a GIT repository!\n\nYou should use a \"git pull\" to update it to the latest version."); return; } if (! AlertWindow::showOkCancelBox (AlertWindow::WarningIcon, "Overwrite Existing JUCE Folder?", - String ("Do you want to overwrite the folder:\n\n" + targetFolder.getFullPathName() + "\n\n..with the latest version from juce.com?\n\n" - "This will move the existing folder to " + targetFolder.getFullPathName() + "_old."))) + "Do you want to replace the folder\n\n" + targetFolderPath + "\n\nwith the latest version from juce.com?\n\n" + "This will move the existing folder to " + targetFolderPath + "_old.")) { return; } } - else + else if (targetFolder.exists()) { - targetFolder = targetFolder.getChildFile ("JUCE").getNonexistentSibling(); + if (! AlertWindow::showOkCancelBox (AlertWindow::WarningIcon, "Existing File Or Directory", + "Do you want to move\n\n" + targetFolderPath + "\n\nto\n\n" + targetFolderPath + "_old?")) + { + return; + } } - downloadAndInstall (targetFolder); + downloadAndInstall (asset, targetFolder); } } -void LatestVersionCheckerAndUpdater::askUserAboutNewVersion (const String& newVersion, const String& releaseNotes) +void LatestVersionCheckerAndUpdater::askUserAboutNewVersion (const String& newVersionString, + const String& releaseNotes, + const VersionInfo::Asset& asset) { - if (newVersion.isNotEmpty() && releaseNotes.isNotEmpty() - && VersionHelpers::isNewVersion (VersionHelpers::getProductVersionString(), newVersion)) - { - dialogWindow = UpdateDialog::launchDialog (newVersion, releaseNotes); + dialogWindow = UpdateDialog::launchDialog (newVersionString, releaseNotes); - if (auto* mm = ModalComponentManager::getInstance()) - mm->attachCallback (dialogWindow.get(), ModalCallbackFunction::create ([this] (int result) - { - if (result == 1) - askUserForLocationToDownload(); + if (auto* mm = ModalComponentManager::getInstance()) + mm->attachCallback (dialogWindow.get(), + ModalCallbackFunction::create ([this, asset] (int result) + { + if (result == 1) + askUserForLocationToDownload (asset); - dialogWindow.reset(); - })); - } + dialogWindow.reset(); + })); } //============================================================================== class DownloadAndInstallThread : private ThreadWithProgressWindow { public: - DownloadAndInstallThread (const URL& u, const File& t, std::function&& cb) + DownloadAndInstallThread (const VersionInfo::Asset& a, const File& t, std::function&& cb) : ThreadWithProgressWindow ("Downloading New Version", true, true), - downloadURL (u), targetFolder (t), completionCallback (std::move (cb)) + asset (a), targetFolder (t), completionCallback (std::move (cb)) { launchThread (3); } @@ -368,7 +332,9 @@ private: result = install (zipData); if (result.failed()) - MessageManager::callAsync ([result] () { AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon, "Installation Failed", result.getErrorMessage()); }); + MessageManager::callAsync ([result] { AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon, + "Installation Failed", + result.getErrorMessage()); }); else MessageManager::callAsync (completionCallback); } @@ -378,10 +344,7 @@ private: setStatusMessage ("Downloading..."); int statusCode = 0; - StringPairArray responseHeaders; - - std::unique_ptr inStream (downloadURL.createInputStream (false, nullptr, nullptr, {}, 0, - &responseHeaders, &statusCode, 0)); + auto inStream = VersionInfo::createInputStreamForAsset (asset, statusCode); if (inStream != nullptr && statusCode == 200) { @@ -406,106 +369,97 @@ private: return Result::ok(); } - return Result::fail ("Failed to download from: " + downloadURL.toString (false)); + return Result::fail ("Failed to download from: " + asset.url); } - Result install (MemoryBlock& data) + Result install (const MemoryBlock& data) { setStatusMessage ("Installing..."); - auto result = unzipDownload (data); - - if (threadShouldExit()) - result = Result::fail ("Cancelled"); - - if (result.failed()) - return result; - - return Result::ok(); - } - - Result unzipDownload (const MemoryBlock& data) - { MemoryInputStream input (data, false); ZipFile zip (input); if (zip.getNumEntries() == 0) return Result::fail ("The downloaded file was not a valid JUCE file!"); - auto unzipTarget = File::createTempFile ({}); + struct ScopedDownloadFolder + { + ScopedDownloadFolder (const File& installTargetFolder) + { + folder = installTargetFolder.getSiblingFile (installTargetFolder.getFileNameWithoutExtension() + "_download").getNonexistentSibling(); + jassert (folder.createDirectory()); + } + + ~ScopedDownloadFolder() { folder.deleteRecursively(); } + + File folder; + }; + + ScopedDownloadFolder unzipTarget (targetFolder); - if (! unzipTarget.createDirectory()) + if (! unzipTarget.folder.isDirectory()) return Result::fail ("Couldn't create a temporary folder to unzip the new version!"); - auto r = zip.uncompressTo (unzipTarget); + auto r = zip.uncompressTo (unzipTarget.folder); if (r.failed()) - { - unzipTarget.deleteRecursively(); return r; - } - r = applyAutoUpdaterFile (unzipTarget); + if (threadShouldExit()) + return Result::fail ("Cancelled"); + + #if JUCE_LINUX || JUCE_MAC + r = setFilePermissions (unzipTarget.folder, zip); if (r.failed()) - { - unzipTarget.deleteRecursively(); return r; - } + + if (threadShouldExit()) + return Result::fail ("Cancelled"); + #endif if (targetFolder.exists()) { auto oldFolder = targetFolder.getSiblingFile (targetFolder.getFileNameWithoutExtension() + "_old").getNonexistentSibling(); if (! targetFolder.moveFileTo (oldFolder)) - { - unzipTarget.deleteRecursively(); return Result::fail ("Could not remove the existing folder!\n\n" "This may happen if you are trying to download into a directory that requires administrator privileges to modify.\n" "Please select a folder that is writable by the current user."); - } } - if (! unzipTarget.moveFileTo (targetFolder)) - { - unzipTarget.deleteRecursively(); + if (! unzipTarget.folder.getChildFile ("JUCE").moveFileTo (targetFolder)) return Result::fail ("Could not overwrite the existing folder!\n\n" "This may happen if you are trying to download into a directory that requires administrator privileges to modify.\n" "Please select a folder that is writable by the current user."); - } return Result::ok(); } - Result applyAutoUpdaterFile (const File& root) + Result setFilePermissions (const File& root, const ZipFile& zip) { - auto autoUpdaterFile = root.getChildFile (".autoupdater.xml"); + constexpr uint32 executableFlag = (1 << 22); - if (autoUpdaterFile.existsAsFile()) + for (int i = 0; i < zip.getNumEntries(); ++i) { - #if JUCE_LINUX || JUCE_MAC - if (auto parent = parseXML (autoUpdaterFile)) + auto* entry = zip.getEntry (i); + + if ((entry->externalFileAttributes & executableFlag) != 0 && entry->filename.getLastCharacter() != '/') { - if (auto* execElement = parent->getChildByName ("EXECUTABLE")) - { - forEachXmlChildElementWithTagName (*execElement, e, "FILE") - { - auto file = root.getChildFile (e->getAllSubText()); - - if (file.exists() && ! file.setExecutePermission (true)) - return Result::fail ("Failed to set executable file permission for " + file.getFileName()); - } - } - } - #endif + auto exeFile = root.getChildFile (entry->filename); - autoUpdaterFile.deleteFile(); + if (! exeFile.exists()) + return Result::fail ("Failed to find executable file when setting permissions " + exeFile.getFileName()); + + if (! exeFile.setExecutePermission (true)) + return Result::fail ("Failed to set executable file permission for " + exeFile.getFileName()); + } } return Result::ok(); } - URL downloadURL; + VersionInfo::Asset asset; File targetFolder; std::function completionCallback; }; @@ -536,9 +490,9 @@ void restartProcess (const File& targetFolder) } } -void LatestVersionCheckerAndUpdater::downloadAndInstall (const File& targetFolder) +void LatestVersionCheckerAndUpdater::downloadAndInstall (const VersionInfo::Asset& asset, const File& targetFolder) { - installer.reset (new DownloadAndInstallThread ({ relativeDownloadPath }, targetFolder, + installer.reset (new DownloadAndInstallThread (asset, targetFolder, [this, targetFolder] { installer.reset(); diff --git a/extras/Projucer/Source/Application/jucer_AutoUpdater.h b/extras/Projucer/Source/Application/jucer_AutoUpdater.h index aa194937..2f4b288b 100644 --- a/extras/Projucer/Source/Application/jucer_AutoUpdater.h +++ b/extras/Projucer/Source/Application/jucer_AutoUpdater.h @@ -26,6 +26,8 @@ #pragma once +#include "../Utility/Helpers/jucer_VersionInfo.h" + class DownloadAndInstallThread; class LatestVersionCheckerAndUpdater : public DeletedAtShutdown, @@ -43,17 +45,12 @@ public: private: //============================================================================== void run() override; - void queryUpdateServer(); - void processResult(); - void askUserAboutNewVersion (const String&, const String&); - void askUserForLocationToDownload(); - void downloadAndInstall (const File&); + void askUserAboutNewVersion (const String&, const String&, const VersionInfo::Asset&); + void askUserForLocationToDownload (const VersionInfo::Asset&); + void downloadAndInstall (const VersionInfo::Asset&, const File&); //============================================================================== bool showAlertWindows = false; - int statusCode = 0; - String relativeDownloadPath; - var jsonReply; std::unique_ptr installer; std::unique_ptr dialogWindow; diff --git a/extras/Projucer/Source/Application/jucer_Headers.h b/extras/Projucer/Source/Application/jucer_Headers.h index 048a9aa3..b96a1bbf 100644 --- a/extras/Projucer/Source/Application/jucer_Headers.h +++ b/extras/Projucer/Source/Application/jucer_Headers.h @@ -26,7 +26,7 @@ #pragma once -#include "../JuceLibraryCode/JuceHeader.h" +#include #include "jucer_CommonHeaders.h" #if JUCE_DEBUG diff --git a/extras/Projucer/Source/Application/jucer_MainWindow.cpp b/extras/Projucer/Source/Application/jucer_MainWindow.cpp index 68d2ddab..8a10d2c0 100644 --- a/extras/Projucer/Source/Application/jucer_MainWindow.cpp +++ b/extras/Projucer/Source/Application/jucer_MainWindow.cpp @@ -50,13 +50,15 @@ MainWindow::MainWindow() setResizable (true, false); centreWithSize (800, 600); - ApplicationCommandManager& commandManager = ProjucerApplication::getCommandManager(); + auto& commandManager = ProjucerApplication::getCommandManager(); - // Register all the app commands.. - commandManager.registerAllCommandsForTarget (this); - commandManager.registerAllCommandsForTarget (getProjectContentComponent()); + auto registerAllAppCommands = [&] + { + commandManager.registerAllCommandsForTarget (this); + commandManager.registerAllCommandsForTarget (getProjectContentComponent()); + }; - // update key mappings.. + auto updateAppKeyMappings = [&] { commandManager.getKeyMappings()->resetToDefaultMappings(); @@ -64,13 +66,13 @@ MainWindow::MainWindow() commandManager.getKeyMappings()->restoreFromXml (*keys); addKeyListener (commandManager.getKeyMappings()); - } + }; - // don't want the window to take focus when the title-bar is clicked.. - setWantsKeyboardFocus (false); + registerAllAppCommands(); + updateAppKeyMappings(); + setWantsKeyboardFocus (false); getLookAndFeel().setColour (ColourSelector::backgroundColourId, Colours::transparentBlack); - projectNameValue.addListener (this); setResizeLimits (600, 500, 32000, 32000); @@ -83,8 +85,6 @@ MainWindow::~MainWindow() #endif removeKeyListener (ProjucerApplication::getCommandManager().getKeyMappings()); - - // save the current size and position to our settings file.. getGlobalProperties().setValue ("lastMainWindowPos", getWindowStateAsString()); clearContentComponent(); @@ -97,7 +97,6 @@ void MainWindow::createProjectContentCompIfNeeded() { clearContentComponent(); setContentOwned (new ProjectContentComponent(), false); - jassert (getProjectContentComponent() != nullptr); } } @@ -119,12 +118,10 @@ void MainWindow::setTitleBarIcon() void MainWindow::makeVisible() { - restoreWindowPosition(); setVisible (true); - addToDesktop(); // (must add before restoring size so that fullscreen will work) + addToDesktop(); restoreWindowPosition(); setTitleBarIcon(); - getContentComponent()->grabKeyboardFocus(); } @@ -138,14 +135,12 @@ void MainWindow::closeButtonPressed() ProjucerApplication::getApp().mainWindowList.closeWindow (this); } -bool MainWindow::closeProject (Project* project, bool askUserToSave) +bool MainWindow::closeCurrentProject (bool askUserToSave) { - jassert (project == currentProject.get() && project != nullptr); - - if (project == nullptr) + if (currentProject == nullptr) return true; - project->getStoredProperties().setValue (getProjectWindowPosName(), getWindowStateAsString()); + currentProject->getStoredProperties().setValue (getProjectWindowPosName(), getWindowStateAsString()); if (auto* pcc = getProjectContentComponent()) { @@ -154,28 +149,24 @@ bool MainWindow::closeProject (Project* project, bool askUserToSave) pcc->hideEditor(); } - if (! ProjucerApplication::getApp().openDocumentManager.closeAllDocumentsUsingProject (*project, askUserToSave)) - return false; - - if (! askUserToSave || (project->saveIfNeededAndUserAgrees() == FileBasedDocument::savedOk)) + if (ProjucerApplication::getApp().openDocumentManager + .closeAllDocumentsUsingProject (*currentProject, askUserToSave)) { - setProject (nullptr); - return true; + if (! askUserToSave || (currentProject->saveIfNeededAndUserAgrees() == FileBasedDocument::savedOk)) + { + setProject (nullptr); + return true; + } } return false; } -bool MainWindow::closeCurrentProject() -{ - return currentProject == nullptr || closeProject (currentProject.get()); -} - void MainWindow::moveProject (File newProjectFileToOpen) { auto openInIDE = currentProject->shouldOpenInIDEAfterSaving(); - closeProject (currentProject.get(), false); + closeCurrentProject (false); openFile (newProjectFileToOpen); if (currentProject != nullptr) @@ -186,21 +177,25 @@ void MainWindow::moveProject (File newProjectFileToOpen) } } -void MainWindow::setProject (Project* newProject) +void MainWindow::setProject (std::unique_ptr newProject) { - createProjectContentCompIfNeeded(); - getProjectContentComponent()->setProject (newProject); - currentProject.reset (newProject); - - if (currentProject != nullptr) - projectNameValue.referTo (currentProject->getProjectValue (Ids::name)); - else + if (newProject == nullptr) + { + getProjectContentComponent()->setProject (nullptr); projectNameValue.referTo (Value()); - if (newProject != nullptr) + currentProject.reset(); + } + else { + currentProject = std::move (newProject); + + createProjectContentCompIfNeeded(); + getProjectContentComponent()->setProject (currentProject.get()); + projectNameValue.referTo (currentProject->getProjectValue (Ids::name)); + if (auto* peer = getPeer()) - peer->setRepresentedFile (newProject->getFile()); + peer->setRepresentedFile (currentProject->getFile()); } ProjucerApplication::getCommandManager().commandStatusChanged(); @@ -232,20 +227,16 @@ bool MainWindow::openFile (const File& file) if (file.hasFileExtension (Project::projectFileExtension)) { - std::unique_ptr newDoc (new Project (file)); - + auto newDoc = std::make_unique (file); auto result = newDoc->loadFrom (file, true); - if (result.wasOk() && closeCurrentProject()) + if (result.wasOk() && closeCurrentProject (true)) { - setProject (newDoc.get()); - newDoc.release()->setChangedFlag (false); + setProject (std::move (newDoc)); + currentProject->setChangedFlag (false); - jassert (getProjectContentComponent() != nullptr); getProjectContentComponent()->reloadLastOpenDocuments(); - - if (auto* p = getProject()) - p->updateDeprecatedProjectSettingsInteractively(); + currentProject->updateDeprecatedProjectSettingsInteractively(); return true; } @@ -606,7 +597,7 @@ bool MainWindowList::askAllWindowsToClose() while (windows.size() > 0) { - if (! windows[0]->closeCurrentProject()) + if (! windows[0]->closeCurrentProject (true)) return false; windows.remove (0); @@ -617,7 +608,7 @@ bool MainWindowList::askAllWindowsToClose() void MainWindowList::createWindowIfNoneAreOpen() { - if (windows.size() == 0) + if (windows.isEmpty()) createNewMainWindow()->showStartPage(); } @@ -633,7 +624,7 @@ void MainWindowList::closeWindow (MainWindow* w) else #endif { - if (w->closeCurrentProject()) + if (w->closeCurrentProject (true)) { windows.removeObject (w); saveCurrentlyOpenProjectList(); @@ -689,22 +680,21 @@ bool MainWindowList::openFile (const File& file, bool openInBackground) WeakReference previousFrontWindow (getFrontmostWindow()); auto* w = getOrCreateEmptyWindow(); - bool ok = w->openFile (file); + jassert (w != nullptr); - if (ok) + if (w->openFile (file)) { w->makeVisible(); - avoidSuperimposedWindows (w); - } - else - { - closeWindow (w); - } + checkWindowBounds (*w); - if (openInBackground && previousFrontWindow != nullptr) - previousFrontWindow->toFront (true); + if (openInBackground && previousFrontWindow != nullptr) + previousFrontWindow->toFront (true); + + return true; + } - return ok; + closeWindow (w); + return false; } if (getFrontmostWindow()->tryToOpenPIP (file)) @@ -718,11 +708,8 @@ bool MainWindowList::openFile (const File& file, bool openInBackground) MainWindow* MainWindowList::createNewMainWindow() { - auto w = new MainWindow(); - windows.add (w); - w->restoreWindowPosition(); - avoidSuperimposedWindows (w); - return w; + windows.add (new MainWindow()); + return windows.getLast(); } MainWindow* MainWindowList::getFrontmostWindow (bool createIfNotFound) @@ -732,8 +719,11 @@ MainWindow* MainWindowList::getFrontmostWindow (bool createIfNotFound) if (createIfNotFound) { auto* w = createNewMainWindow(); - avoidSuperimposedWindows (w); + jassert (w != nullptr); + w->makeVisible(); + checkWindowBounds (*w); + return w; } @@ -784,29 +774,52 @@ MainWindow* MainWindowList::getMainWindowForFile (const File& file) return nullptr; } -void MainWindowList::avoidSuperimposedWindows (MainWindow* const mw) +void MainWindowList::checkWindowBounds (MainWindow& windowToCheck) { - for (int i = windows.size(); --i >= 0;) + auto avoidSuperimposedWindows = [&] { - auto* other = windows.getUnchecked(i); + for (auto* otherWindow : windows) + { + if (otherWindow == nullptr || otherWindow == &windowToCheck) + continue; - auto b1 = mw->getBounds(); - auto b2 = other->getBounds(); + auto boundsToCheck = windowToCheck.getScreenBounds(); + auto otherBounds = otherWindow->getScreenBounds(); - if (mw != other - && std::abs (b1.getX() - b2.getX()) < 3 - && std::abs (b1.getY() - b2.getY()) < 3 - && std::abs (b1.getRight() - b2.getRight()) < 3 - && std::abs (b1.getBottom() - b2.getBottom()) < 3) - { - int dx = 40, dy = 30; + if (std::abs (boundsToCheck.getX() - otherBounds.getX()) < 3 + && std::abs (boundsToCheck.getY() - otherBounds.getY()) < 3 + && std::abs (boundsToCheck.getRight() - otherBounds.getRight()) < 3 + && std::abs (boundsToCheck.getBottom() - otherBounds.getBottom()) < 3) + { + int dx = 40, dy = 30; - if (b1.getCentreX() >= mw->getScreenBounds().getCentreX()) dx = -dx; - if (b1.getCentreY() >= mw->getScreenBounds().getCentreY()) dy = -dy; + if (otherBounds.getCentreX() >= boundsToCheck.getCentreX()) dx = -dx; + if (otherBounds.getCentreY() >= boundsToCheck.getCentreY()) dy = -dy; - mw->setBounds (b1.translated (dx, dy)); + windowToCheck.setBounds (boundsToCheck.translated (dx, dy)); + } } - } + }; + + auto ensureWindowIsFullyOnscreen = [&] + { + auto windowBounds = windowToCheck.getScreenBounds(); + auto screenLimits = Desktop::getInstance().getDisplays().findDisplayForRect (windowBounds).userArea; + + if (auto* peer = windowToCheck.getPeer()) + peer->getFrameSize().subtractFrom (screenLimits); + + auto constrainedX = jlimit (screenLimits.getX(), jmax (screenLimits.getX(), screenLimits.getRight() - windowBounds.getWidth()), windowBounds.getX()); + auto constrainedY = jlimit (screenLimits.getY(), jmax (screenLimits.getY(), screenLimits.getBottom() - windowBounds.getHeight()), windowBounds.getY()); + + Point constrainedTopLeft (constrainedX, constrainedY); + + if (windowBounds.getPosition() != constrainedTopLeft) + windowToCheck.setTopLeftPosition (constrainedTopLeft); + }; + + avoidSuperimposedWindows(); + ensureWindowIsFullyOnscreen(); } void MainWindowList::saveCurrentlyOpenProjectList() diff --git a/extras/Projucer/Source/Application/jucer_MainWindow.h b/extras/Projucer/Source/Application/jucer_MainWindow.h index 919691f7..43de4be5 100644 --- a/extras/Projucer/Source/Application/jucer_MainWindow.h +++ b/extras/Projucer/Source/Application/jucer_MainWindow.h @@ -50,14 +50,15 @@ public: //============================================================================== bool canOpenFile (const File& file) const; bool openFile (const File& file); - void setProject (Project* newProject); - Project* getProject() const { return currentProject.get(); } + + void setProject (std::unique_ptr newProject); + Project* getProject() const { return currentProject.get(); } + bool tryToOpenPIP (const File& f); void makeVisible(); void restoreWindowPosition(); - bool closeProject (Project* project, bool askToSave = true); - bool closeCurrentProject(); + bool closeCurrentProject (bool askToSave); void moveProject (File newProjectFile); void showStartPage(); @@ -118,7 +119,7 @@ public: void reopenLastProjects(); void saveCurrentlyOpenProjectList(); - void avoidSuperimposedWindows (MainWindow*); + void checkWindowBounds (MainWindow&); void sendLookAndFeelChange(); diff --git a/extras/Projucer/Source/BinaryData/Templates/jucer_ComponentTemplate.h b/extras/Projucer/Source/BinaryData/Templates/jucer_ComponentTemplate.h index d47a3987..ffaafbfc 100644 --- a/extras/Projucer/Source/BinaryData/Templates/jucer_ComponentTemplate.h +++ b/extras/Projucer/Source/BinaryData/Templates/jucer_ComponentTemplate.h @@ -20,7 +20,7 @@ #pragma once //[Headers] -- You can add your own extra header files here -- -%%include_juce_header%% +%%include_juce%% //[/Headers] %%include_files_h%% @@ -38,7 +38,7 @@ public: //============================================================================== %%class_name%% (%%constructor_params%%); - ~%%class_name%%(); + ~%%class_name%%() override; //============================================================================== //[UserMethods] -- You can add your own custom methods in this section. diff --git a/extras/Projucer/Source/BinaryData/Templates/jucer_PIPMain.cpp b/extras/Projucer/Source/BinaryData/Templates/jucer_PIPMain.cpp index c26a2d04..da0677bd 100644 --- a/extras/Projucer/Source/BinaryData/Templates/jucer_PIPMain.cpp +++ b/extras/Projucer/Source/BinaryData/Templates/jucer_PIPMain.cpp @@ -6,7 +6,7 @@ ============================================================================== */ -#include "../JuceLibraryCode/JuceHeader.h" +%%include_juce%% #include "%%filename%%" %%component_begin%% diff --git a/extras/Projucer/Source/ComponentEditor/PaintElements/jucer_PaintElementImage.cpp b/extras/Projucer/Source/ComponentEditor/PaintElements/jucer_PaintElementImage.cpp index 5b6a4a4f..0ab74221 100644 --- a/extras/Projucer/Source/ComponentEditor/PaintElements/jucer_PaintElementImage.cpp +++ b/extras/Projucer/Source/ComponentEditor/PaintElements/jucer_PaintElementImage.cpp @@ -145,8 +145,8 @@ void PaintElementImage::fillInGeneratedCode (GeneratedCode& code, String& paintM else r << " g.setColour (Colours::black.withAlpha (" << CodeHelpers::floatLiteral (opacity, 3) << "));\n"; - r << " jassert (" << imageVariable << " != 0);\n" - << " if (" << imageVariable << " != 0)\n" + r << " jassert (" << imageVariable << " != nullptr);\n" + << " if (" << imageVariable << " != nullptr)\n" << " " << imageVariable << "->drawWithin (g, Rectangle (x, y, width, height).toFloat(),\n" << " " << String::repeatedString (" ", imageVariable.length() + 18) << (mode == stretched ? "RectanglePlacement::stretchToFit" diff --git a/extras/Projucer/Source/ComponentEditor/jucer_GeneratedCode.cpp b/extras/Projucer/Source/ComponentEditor/jucer_GeneratedCode.cpp index 0b43f9ee..a63a13fe 100644 --- a/extras/Projucer/Source/ComponentEditor/jucer_GeneratedCode.cpp +++ b/extras/Projucer/Source/ComponentEditor/jucer_GeneratedCode.cpp @@ -319,10 +319,7 @@ static void copyAcrossUserSections (String& dest, const String& src) } //============================================================================== -void GeneratedCode::applyToCode (String& code, - const File& targetFile, - const String& oldFileWithUserData, - Project* project) const +void GeneratedCode::applyToCode (String& code, const File& targetFile, const String& oldFileWithUserData) const { replaceTemplate (code, "version", JUCEApplicationBase::getInstance()->getApplicationVersion()); replaceTemplate (code, "creationTime", Time::getCurrentTime().toString (true, true, true)); @@ -337,11 +334,8 @@ void GeneratedCode::applyToCode (String& code, replaceTemplate (code, "method_definitions", getCallbackDefinitions()); - File juceHeaderFile = project != nullptr ? project->getAppIncludeFile() - : targetFile.getSiblingFile ("JuceHeader.h"); - - replaceTemplate (code, "include_juce_header", CodeHelpers::createIncludeStatement (juceHeaderFile, targetFile)); - + replaceTemplate (code, "include_juce", CodeHelpers::createIncludePathIncludeStatement (Project::getJuceSourceHFilename())); + replaceTemplate (code, "include_files_h", getIncludeFileCode (includeFilesH, targetFile)); replaceTemplate (code, "include_files_cpp", getIncludeFileCode (includeFilesCPP, targetFile)); diff --git a/extras/Projucer/Source/ComponentEditor/jucer_GeneratedCode.h b/extras/Projucer/Source/ComponentEditor/jucer_GeneratedCode.h index 29eda964..5f62f35d 100644 --- a/extras/Projucer/Source/ComponentEditor/jucer_GeneratedCode.h +++ b/extras/Projucer/Source/ComponentEditor/jucer_GeneratedCode.h @@ -41,11 +41,7 @@ public: ~GeneratedCode(); //============================================================================== - void applyToCode (String& code, - const File& targetFile, - const String& oldFileWithUserData, - Project* project) const; - + void applyToCode (String& code, const File& targetFile, const String& oldFileWithUserData) const; int getUniqueSuffix(); //============================================================================== @@ -54,7 +50,7 @@ public: String className; String componentName; String parentClassInitialiser; // optional parent class initialiser to go before the items in the initialisers list - StringArray initialisers; // (a list of the member variables that need initalising after the constructor declaration) + StringArray initialisers; // (a list of the member variables that need initialising after the constructor declaration) String parentClasses; String constructorParams; String privateMemberDeclarations; diff --git a/extras/Projucer/Source/ComponentEditor/jucer_JucerDocument.cpp b/extras/Projucer/Source/ComponentEditor/jucer_JucerDocument.cpp index dea80bcd..ad1e8a8e 100644 --- a/extras/Projucer/Source/ComponentEditor/jucer_JucerDocument.cpp +++ b/extras/Projucer/Source/ComponentEditor/jucer_JucerDocument.cpp @@ -532,11 +532,8 @@ bool JucerDocument::flushChangesToDocuments (Project* project, bool isInitial) String existingHeader (header->getCodeDocument().getAllContent()); String existingCpp (cpp->getCodeDocument().getAllContent()); - generated.applyToCode (headerTemplate, headerFile, - existingHeader, project); - - generated.applyToCode (cppTemplate, headerFile.withFileExtension (".cpp"), - existingCpp, project); + generated.applyToCode (headerTemplate, headerFile, existingHeader); + generated.applyToCode (cppTemplate, headerFile.withFileExtension (".cpp"), existingCpp); if (isInitial) { diff --git a/extras/Projucer/Source/LiveBuildEngine/jucer_CompileEngineClient.cpp b/extras/Projucer/Source/LiveBuildEngine/jucer_CompileEngineClient.cpp index 40d6767e..d852991a 100644 --- a/extras/Projucer/Source/LiveBuildEngine/jucer_CompileEngineClient.cpp +++ b/extras/Projucer/Source/LiveBuildEngine/jucer_CompileEngineClient.cpp @@ -336,9 +336,6 @@ private: if (exporter->canLaunchProject()) defs.add (exporter->getExporterIdentifierMacro() + "=1"); - // Use the JUCE implementation of std::function until the live build - // engine can compile the one from the standard library - defs.add (" _LIBCPP_FUNCTIONAL=1"); defs.removeEmptyStrings(); return defs.joinIntoString (" "); @@ -380,7 +377,7 @@ private: auto isVSTHost = project.getEnabledModules().isModuleEnabled ("juce_audio_processors") && (project.isConfigFlagEnabled ("JUCE_PLUGINHOST_VST3") || project.isConfigFlagEnabled ("JUCE_PLUGINHOST_VST")); - auto isPluginProject = proj.getProjectType().isAudioPlugin(); + auto isPluginProject = proj.isAudioPluginProject(); OwnedArray modules; proj.getEnabledModules().createRequiredModules (modules); @@ -462,6 +459,7 @@ private: StringArray getSystemIncludePaths() { StringArray paths; + paths.add (project.getGeneratedCodeFolder().getFullPathName()); paths.addArray (getSearchPathsFromString (project.getCompileEngineSettings().getSystemHeaderPathString())); auto isVSTHost = project.getEnabledModules().isModuleEnabled ("juce_audio_processors") @@ -470,7 +468,7 @@ private: auto customVst3Path = getAppSettings().getStoredPath (Ids::vst3Path, TargetOS::getThisOS()).get().toString(); - if (customVst3Path.isNotEmpty() && (project.getProjectType().isAudioPlugin() || isVSTHost)) + if (customVst3Path.isNotEmpty() && (project.isAudioPluginProject() || isVSTHost)) paths.add (customVst3Path); OwnedArray modules; @@ -480,7 +478,7 @@ private: { paths.addIfNotAlreadyThere (module->getFolder().getParentDirectory().getFullPathName()); - if (customVst3Path.isEmpty() && (project.getProjectType().isAudioPlugin() || isVSTHost)) + if (customVst3Path.isEmpty() && (project.isAudioPluginProject() || isVSTHost)) if (module->getID() == "juce_audio_processors") paths.addIfNotAlreadyThere (module->getFolder().getChildFile ("format_types").getChildFile ("VST3_SDK").getFullPathName()); } diff --git a/extras/Projucer/Source/LiveBuildEngine/jucer_DownloadCompileEngineThread.cpp b/extras/Projucer/Source/LiveBuildEngine/jucer_DownloadCompileEngineThread.cpp index b3273dee..5b657500 100644 --- a/extras/Projucer/Source/LiveBuildEngine/jucer_DownloadCompileEngineThread.cpp +++ b/extras/Projucer/Source/LiveBuildEngine/jucer_DownloadCompileEngineThread.cpp @@ -27,6 +27,7 @@ #include "../Application/jucer_Headers.h" #include "jucer_DownloadCompileEngineThread.h" #include "../LiveBuildEngine/jucer_CompileEngineDLL.h" +#include "../Utility/Helpers/jucer_VersionInfo.h" //============================================================================== bool DownloadCompileEngineThread::downloadAndInstall() @@ -83,38 +84,60 @@ void DownloadCompileEngineThread::run() Result DownloadCompileEngineThread::download (MemoryBlock& dest) { - int statusCode = 302; - const int timeoutMs = 10000; - StringPairArray responseHeaders; + auto info = VersionInfo::fetchFromUpdateServer (ProjectInfo::versionString); - URL url = getDownloadUrl(); - std::unique_ptr in (url.createInputStream (false, nullptr, nullptr, - String(), timeoutMs, &responseHeaders, - &statusCode, 0)); + if (info == nullptr) + return Result::fail ("Download error: cannot communicate with server"); - if (in == nullptr || statusCode != 200) - return Result::fail ("Download error: cannot establish connection"); + auto requiredAssetName = [] + { + String name ("JUCECompileEngine_"); - MemoryOutputStream mo (dest, true); + #if JUCE_MAC + name << "osx_"; + #elif JUCE_WINDOWS + name << "windows_"; + #else + jassertfalse; + #endif - int64 size = in->getTotalLength(); - int64 bytesReceived = -1; - String msg("Downloading... (123)"); + return name + ProjectInfo::versionString + ".zip"; + }(); - for (int64 pos = 0; pos < size; pos += bytesReceived) + for (auto& asset : info->assets) { - setStatusMessage (msg.replace ("123", File::descriptionOfSizeInBytes (pos))); + if (asset.name == requiredAssetName) + { + int statusCode = 0; + auto in = VersionInfo::createInputStreamForAsset (asset, statusCode); + + if (in == nullptr || statusCode != 200) + return Result::fail ("Download error: cannot establish connection"); + + MemoryOutputStream mo (dest, true); + + int64 size = in->getTotalLength(); + int64 bytesReceived = -1; + String msg("Downloading... (123)"); + + for (int64 pos = 0; pos < size; pos += bytesReceived) + { + setStatusMessage (msg.replace ("123", File::descriptionOfSizeInBytes (pos))); + + if (threadShouldExit()) + return Result::fail ("Download error: operation interrupted"); - if (threadShouldExit()) - return Result::fail ("Download error: operation interrupted"); + bytesReceived = mo.writeFromInputStream (*in, 8192); - bytesReceived = mo.writeFromInputStream (*in, 8192); + if (bytesReceived == 0) + return Result::fail ("Download error: lost connection"); + } - if (bytesReceived == 0) - return Result::fail ("Download error: lost connection"); + return Result::ok(); + } } - return Result::ok(); + return Result::fail ("Download error: no downloads available"); } Result DownloadCompileEngineThread::install (const MemoryBlock& data, File& targetFolder) @@ -131,21 +154,6 @@ Result DownloadCompileEngineThread::install (const MemoryBlock& data, File& targ return zip.uncompressTo (targetFolder); } -URL DownloadCompileEngineThread::getDownloadUrl() -{ - String urlStub ("http://assets.roli.com/juce/JUCECompileEngine_"); - - #if JUCE_MAC - urlStub << "osx_"; - #elif JUCE_WINDOWS - urlStub << "windows_"; - #else - jassertfalse; - #endif - - return urlStub + ProjectInfo::versionString + ".zip"; -} - File DownloadCompileEngineThread::getInstallFolder() { return CompileEngineDLL::getVersionedUserAppSupportFolder(); diff --git a/extras/Projucer/Source/Project/UI/Sidebar/jucer_ModuleTreeItems.h b/extras/Projucer/Source/Project/UI/Sidebar/jucer_ModuleTreeItems.h index 9cee8477..7917a4fd 100644 --- a/extras/Projucer/Source/Project/UI/Sidebar/jucer_ModuleTreeItems.h +++ b/extras/Projucer/Source/Project/UI/Sidebar/jucer_ModuleTreeItems.h @@ -151,6 +151,7 @@ private: props.add (new CppStandardWarningComponent()); group.properties.clear(); + exporterModulePathDefaultValues.clear(); exporterModulePathValues.clear(); for (Project::ExporterIterator exporter (project); exporter.next();) @@ -158,23 +159,32 @@ private: if (exporter->isCLion()) continue; - exporterModulePathValues.add (exporter->getPathForModuleValue (moduleID)); + exporterModulePathDefaultValues.add (exporter->getPathForModuleValue (moduleID)); + auto& defaultValue = exporterModulePathDefaultValues.getReference (exporterModulePathDefaultValues.size() - 1); - auto& value = exporterModulePathValues.getReference (exporterModulePathValues.size() - 1); - value.onDefaultChange = [this] { startTimer (50); }; + exporterModulePathValues.add (defaultValue.getPropertyAsValue()); - auto* pathComponent = new FilePathPropertyComponent (value, "Path for " + exporter->getName().quoted(), true, - exporter->getTargetOSForExporter() == TargetOS::getThisOS(), - "*", project.getProjectFolder()); + auto pathComponent = std::make_unique (defaultValue, + "Path for " + exporter->getName().quoted(), + true, + exporter->getTargetOSForExporter() == TargetOS::getThisOS(), + "*", + project.getProjectFolder()); - props.add (pathComponent, + pathComponent->setEnabled (! modules.shouldUseGlobalPath (moduleID)); + + props.add (pathComponent.release(), "A path to the folder that contains the " + moduleID + " module when compiling the " + exporter->getName().quoted() + " target. " "This can be an absolute path, or relative to the jucer project folder, but it " "must be valid on the filesystem of the target machine that will be performing this build. If this " "is empty then the global path will be used."); + } - pathComponent->setEnabled (! modules.shouldUseGlobalPath (moduleID)); + for (int i = 0; i < exporterModulePathDefaultValues.size(); ++i) + { + exporterModulePathDefaultValues.getReference (i).onDefaultChange = [this] { startTimer (50); }; + exporterModulePathValues.getReference (i).addListener (this); } globalPathValue.removeListener (this); @@ -227,11 +237,32 @@ private: String getModuleID() const noexcept { return moduleID; } private: - void valueChanged (Value&) override { startTimer (50); } - void timerCallback() override { stopTimer(); refresh(); } + void valueChanged (Value& v) override + { + auto isExporterPathValue = [&] + { + for (auto& exporterValue : exporterModulePathValues) + if (exporterValue.refersToSameSourceAs (v)) + return true; + + return false; + }(); + + if (isExporterPathValue) + project.rescanExporterPathModules(); + + startTimer (50); + } + + void timerCallback() override + { + stopTimer(); + refresh(); + } //============================================================================== - Array exporterModulePathValues; + Array exporterModulePathDefaultValues; + Array exporterModulePathValues; Value globalPathValue; OwnedArray configFlags; diff --git a/extras/Projucer/Source/Project/UI/jucer_ProjectContentComponent.cpp b/extras/Projucer/Source/Project/UI/jucer_ProjectContentComponent.cpp index 8e3a367c..052e3c00 100644 --- a/extras/Projucer/Source/Project/UI/jucer_ProjectContentComponent.cpp +++ b/extras/Projucer/Source/Project/UI/jucer_ProjectContentComponent.cpp @@ -559,7 +559,7 @@ bool ProjectContentComponent::saveProject (bool shouldWait, bool openInIDE) void ProjectContentComponent::closeProject() { if (auto* mw = findParentComponentOfClass()) - mw->closeCurrentProject(); + mw->closeCurrentProject (true); } void ProjectContentComponent::showProjectSettings() diff --git a/extras/Projucer/Source/Project/jucer_Module.cpp b/extras/Projucer/Source/Project/jucer_Module.cpp index e33a28f5..a81d322c 100644 --- a/extras/Projucer/Source/Project/jucer_Module.cpp +++ b/extras/Projucer/Source/Project/jucer_Module.cpp @@ -302,7 +302,12 @@ void LibraryModule::addSettingsForModuleToExporter (ProjectExporter& exporter, P auto& xcodeExporter = dynamic_cast (exporter); if (project.isAUPluginHost()) - xcodeExporter.xcodeFrameworks.addTokens (xcodeExporter.isOSX() ? "AudioUnit CoreAudioKit" : "CoreAudioKit", false); + { + xcodeExporter.xcodeFrameworks.add ("CoreAudioKit"); + + if (xcodeExporter.isOSX()) + xcodeExporter.xcodeFrameworks.add ("AudioUnit"); + } auto frameworks = moduleInfo.moduleInfo [xcodeExporter.isOSX() ? "OSXFrameworks" : "iOSFrameworks"].toString(); xcodeExporter.xcodeFrameworks.addTokens (frameworks, ", ", {}); @@ -566,7 +571,7 @@ bool EnabledModuleList::isModuleEnabled (const String& moduleID) const bool EnabledModuleList::isAudioPluginModuleMissing() const { - return project.getProjectType().isAudioPlugin() + return project.isAudioPluginProject() && ! isModuleEnabled ("juce_audio_plugin_client"); } diff --git a/extras/Projucer/Source/Project/jucer_Project.cpp b/extras/Projucer/Source/Project/jucer_Project.cpp index 45f5b351..9d760505 100644 --- a/extras/Projucer/Source/Project/jucer_Project.cpp +++ b/extras/Projucer/Source/Project/jucer_Project.cpp @@ -326,6 +326,7 @@ void Project::removeDefunctExporters() oldExporters.set ("MSVC6", "MSVC6"); oldExporters.set ("VS2010", "Visual Studio 2010"); oldExporters.set ("VS2012", "Visual Studio 2012"); + oldExporters.set ("VS2013", "Visual Studio 2013"); for (auto& key : oldExporters.getAllKeys()) { @@ -514,7 +515,7 @@ static int getJuceVersion (const String& v) + getVersionElement (v, 0); } -static int getBuiltJuceVersion() +static constexpr int getBuiltJuceVersion() { return JUCE_MAJOR_VERSION * 100000 + JUCE_MINOR_VERSION * 1000 @@ -523,11 +524,7 @@ static int getBuiltJuceVersion() static bool isModuleNewerThanProjucer (const ModuleDescription& module) { - if (module.getID().startsWith ("juce_") - && getJuceVersion (module.getVersion()) > getBuiltJuceVersion()) - return true; - - return false; + return module.getID().startsWith ("juce_") && getJuceVersion (module.getVersion()) > getBuiltJuceVersion(); } void Project::warnAboutOldProjucerVersion() @@ -536,7 +533,6 @@ void Project::warnAboutOldProjucerVersion() { if (isModuleNewerThanProjucer ({ juceModule.second })) { - // Projucer is out of date! if (ProjucerApplication::getApp().isRunningCommandLine) std::cout << "WARNING! This version of the Projucer is out-of-date!" << std::endl; else @@ -1010,7 +1006,7 @@ void Project::createPropertyEditors (PropertyListBuilder& props) props.add (new TextPropertyComponent (bundleIdentifierValue, "Bundle Identifier", 256, false), "A unique identifier for this product, mainly for use in OSX/iOS builds. It should be something like 'com.yourcompanyname.yourproductname'"); - if (getProjectType().isAudioPlugin()) + if (isAudioPluginProject()) createAudioPluginPropertyEditors (props); { diff --git a/extras/Projucer/Source/Project/jucer_Project.h b/extras/Projucer/Source/Project/jucer_Project.h index 16b8be9d..80711e8b 100644 --- a/extras/Projucer/Source/Project/jucer_Project.h +++ b/extras/Projucer/Source/Project/jucer_Project.h @@ -67,9 +67,8 @@ public: File getBinaryDataCppFile (int index) const; File getBinaryDataHeaderFile() const { return getBinaryDataCppFile (0).withFileExtension (".h"); } - String getAppConfigFilename() const { return "AppConfig.h"; } - String getJuceSourceFilenameRoot() const { return "JuceLibraryCode"; } - String getJuceSourceHFilename() const { return "JuceHeader.h"; } + static String getAppConfigFilename() { return "AppConfig.h"; } + static String getJuceSourceHFilename() { return "JuceHeader.h"; } //============================================================================== template @@ -148,7 +147,6 @@ public: String getVSTNumMIDIInputsString() const { return pluginVSTNumMidiInputsValue.get(); } String getVSTNumMIDIOutputsString() const { return pluginVSTNumMidiOutputsValue.get(); } - //============================================================================== static bool checkMultiChoiceVar (const ValueWithDefault& valueToCheck, Identifier idToCheck) noexcept { if (! valueToCheck.get().isArray()) @@ -162,18 +160,18 @@ public: return false; } - //============================================================================== - bool shouldBuildVST() const { return checkMultiChoiceVar (pluginFormatsValue, Ids::buildVST); } - bool shouldBuildVST3() const { return checkMultiChoiceVar (pluginFormatsValue, Ids::buildVST3); } - bool shouldBuildAU() const { return checkMultiChoiceVar (pluginFormatsValue, Ids::buildAU); } - bool shouldBuildAUv3() const { return checkMultiChoiceVar (pluginFormatsValue, Ids::buildAUv3); } - bool shouldBuildRTAS() const { return checkMultiChoiceVar (pluginFormatsValue, Ids::buildRTAS); } - bool shouldBuildAAX() const { return checkMultiChoiceVar (pluginFormatsValue, Ids::buildAAX); } - bool shouldBuildStandalonePlugin() const { return checkMultiChoiceVar (pluginFormatsValue, Ids::buildStandalone); } - bool shouldBuildUnityPlugin() const { return checkMultiChoiceVar (pluginFormatsValue, Ids::buildUnity); } - bool shouldEnableIAA() const { return checkMultiChoiceVar (pluginFormatsValue, Ids::enableIAA); } + bool isAudioPluginProject() const { return getProjectType().isAudioPlugin(); } + + bool shouldBuildVST() const { return isAudioPluginProject() && checkMultiChoiceVar (pluginFormatsValue, Ids::buildVST); } + bool shouldBuildVST3() const { return isAudioPluginProject() && checkMultiChoiceVar (pluginFormatsValue, Ids::buildVST3); } + bool shouldBuildAU() const { return isAudioPluginProject() && checkMultiChoiceVar (pluginFormatsValue, Ids::buildAU); } + bool shouldBuildAUv3() const { return isAudioPluginProject() && checkMultiChoiceVar (pluginFormatsValue, Ids::buildAUv3); } + bool shouldBuildRTAS() const { return isAudioPluginProject() && checkMultiChoiceVar (pluginFormatsValue, Ids::buildRTAS); } + bool shouldBuildAAX() const { return isAudioPluginProject() && checkMultiChoiceVar (pluginFormatsValue, Ids::buildAAX); } + bool shouldBuildStandalonePlugin() const { return isAudioPluginProject() && checkMultiChoiceVar (pluginFormatsValue, Ids::buildStandalone); } + bool shouldBuildUnityPlugin() const { return isAudioPluginProject() && checkMultiChoiceVar (pluginFormatsValue, Ids::buildUnity); } + bool shouldEnableIAA() const { return isAudioPluginProject() && checkMultiChoiceVar (pluginFormatsValue, Ids::enableIAA); } - //============================================================================== bool isPluginSynth() const { return checkMultiChoiceVar (pluginCharacteristicsValue, Ids::pluginIsSynth); } bool pluginWantsMidiInput() const { return checkMultiChoiceVar (pluginCharacteristicsValue, Ids::pluginWantsMidiIn); } bool pluginProducesMidiOutput() const { return checkMultiChoiceVar (pluginCharacteristicsValue, Ids::pluginProducesMidiOut); } @@ -184,7 +182,6 @@ public: bool isPluginAAXBypassDisabled() const { return checkMultiChoiceVar (pluginCharacteristicsValue, Ids::pluginAAXDisableBypass); } bool isPluginAAXMultiMonoDisabled() const { return checkMultiChoiceVar (pluginCharacteristicsValue, Ids::pluginAAXDisableMultiMono); } - //============================================================================== static StringArray getAllAUMainTypeStrings() noexcept; static Array getAllAUMainTypeVars() noexcept; Array getDefaultAUMainTypes() const noexcept; diff --git a/extras/Projucer/Source/ProjectSaving/jucer_ProjectExport_Android.h b/extras/Projucer/Source/ProjectSaving/jucer_ProjectExport_Android.h index cc24249b..bed3870d 100644 --- a/extras/Projucer/Source/ProjectSaving/jucer_ProjectExport_Android.h +++ b/extras/Projucer/Source/ProjectSaving/jucer_ProjectExport_Android.h @@ -140,9 +140,9 @@ public: androidKeyStorePass (settings, Ids::androidKeyStorePass, getUndoManager(), "android"), androidKeyAlias (settings, Ids::androidKeyAlias, getUndoManager(), "androiddebugkey"), androidKeyAliasPass (settings, Ids::androidKeyAliasPass, getUndoManager(), "android"), - gradleVersion (settings, Ids::gradleVersion, getUndoManager(), "4.10"), + gradleVersion (settings, Ids::gradleVersion, getUndoManager(), "5.4.1"), gradleToolchain (settings, Ids::gradleToolchain, getUndoManager(), "clang"), - androidPluginVersion (settings, Ids::androidPluginVersion, getUndoManager(), "3.2.1"), + androidPluginVersion (settings, Ids::androidPluginVersion, getUndoManager(), "3.5.3"), AndroidExecutable (getAppSettings().getStoredPath (Ids::androidStudioExePath, TargetOS::getThisOS()).get().toString()) { name = getName(); @@ -840,6 +840,9 @@ private: for (auto& d : StringArray::fromLines (androidJavaLibs.get().toString())) mo << " implementation files('libs/" << File (d).getFileName() << "')" << newLine; + if (isInAppBillingEnabled()) + mo << " implementation 'com.android.billingclient:billing:2.1.0'" << newLine; + if (areRemoteNotificationsEnabled()) { mo << " implementation 'com.google.firebase:firebase-core:16.0.1'" << newLine; @@ -909,6 +912,9 @@ private: if (areRemoteNotificationsEnabled()) addOptJavaFolderToSourceSetsForModule (javaSourceSets, modules, "juce_gui_extra"); + if (project.getEnabledModules().isModuleEnabled ("juce_product_unlocking") && isInAppBillingEnabled()) + addOptJavaFolderToSourceSetsForModule (javaSourceSets, modules, "juce_product_unlocking"); + MemoryOutputStream mo; mo.setNewLineString ("\n"); @@ -1215,20 +1221,13 @@ private: bool arePushNotificationsEnabled() const { return androidPushNotifications.get(); } bool areRemoteNotificationsEnabled() const { return arePushNotificationsEnabled() && androidEnableRemoteNotifications.get(); } + bool isInAppBillingEnabled() const { return androidInAppBillingPermission.get(); } + String getJNIActivityClassName() const { return getActivityClassString().replaceCharacter ('.', '/'); } - static LibraryModule* getCoreModule (const OwnedArray& modules) - { - for (int i = modules.size(); --i >= 0;) - if (modules.getUnchecked (i)->getID() == "juce_core") - return modules.getUnchecked (i); - - return nullptr; - } - //============================================================================== String getNativeModuleBinaryName (const AndroidBuildConfiguration& config) const { @@ -1351,7 +1350,7 @@ private: mo << " \"" << file.toUnixStyle() << "\"" << newLine; if ((! projectItem.shouldBeCompiled()) || (! shouldFileBeCompiledByDefault (f)) - || (getProject().getProjectType().isAudioPlugin() + || (getProject().isAudioPluginProject() && targetType != ProjectType::Target::SharedCodeTarget && targetType != ProjectType::Target::StandalonePlugIn)) { @@ -1442,10 +1441,10 @@ private: if (arePushNotificationsEnabled()) { defines.set ("JUCE_PUSH_NOTIFICATIONS", "1"); - defines.set ("JUCE_PUSH_NOTIFICATIONS_ACTIVITY", String::formatted("\"%s\"", getJNIActivityClassName().toUTF8())); + defines.set ("JUCE_PUSH_NOTIFICATIONS_ACTIVITY", getJNIActivityClassName().quoted()); } - if (androidInAppBillingPermission.get()) + if (isInAppBillingEnabled()) defines.set ("JUCE_IN_APP_PURCHASES", "1"); if (supportsGLv3()) @@ -1808,7 +1807,10 @@ private: StringArray s = StringArray::fromTokens (androidOtherPermissions.get().toString(), ", ", {}); if (androidInternetNeeded.get()) + { s.add ("android.permission.INTERNET"); + s.add ("android.permission.CHANGE_WIFI_MULTICAST_STATE"); + } if (androidMicNeeded.get()) s.add ("android.permission.RECORD_AUDIO"); @@ -1829,7 +1831,7 @@ private: if (androidExternalWritePermission.get()) s.add ("android.permission.WRITE_EXTERNAL_STORAGE"); - if (androidInAppBillingPermission.get()) + if (isInAppBillingEnabled()) s.add ("com.android.vending.BILLING"); if (androidVibratePermission.get()) diff --git a/extras/Projucer/Source/ProjectSaving/jucer_ProjectExport_CLion.h b/extras/Projucer/Source/ProjectSaving/jucer_ProjectExport_CLion.h index 0384e55f..df743afd 100644 --- a/extras/Projucer/Source/ProjectSaving/jucer_ProjectExport_CLion.h +++ b/extras/Projucer/Source/ProjectSaving/jucer_ProjectExport_CLion.h @@ -304,7 +304,7 @@ private: template void getFileInfoList (Target& target, Exporter& exporter, const Project::Item& projectItem, std::vector>& fileInfoList) const { - auto targetType = (getProject().getProjectType().isAudioPlugin() ? target.type : Target::Type::SharedCodeTarget); + auto targetType = (getProject().isAudioPluginProject() ? target.type : Target::Type::SharedCodeTarget); if (projectItem.isGroup()) { diff --git a/extras/Projucer/Source/ProjectSaving/jucer_ProjectExport_CodeBlocks.h b/extras/Projucer/Source/ProjectSaving/jucer_ProjectExport_CodeBlocks.h index 722b566a..c43928e6 100644 --- a/extras/Projucer/Source/ProjectSaving/jucer_ProjectExport_CodeBlocks.h +++ b/extras/Projucer/Source/ProjectSaving/jucer_ProjectExport_CodeBlocks.h @@ -432,7 +432,7 @@ private: if (config.exporter.isLinux()) { - if (target.isDynamicLibrary() || getProject().getProjectType().isAudioPlugin()) + if (target.isDynamicLibrary() || getProject().isAudioPluginProject()) flags.add ("-fPIC"); auto packages = getPackages(); @@ -495,7 +495,7 @@ private: { auto librarySearchPaths = config.getLibrarySearchPaths(); - if (getProject().getProjectType().isAudioPlugin() && target.type != ProjectType::Target::SharedCodeTarget) + if (getProject().isAudioPluginProject() && target.type != ProjectType::Target::SharedCodeTarget) librarySearchPaths.add (RelativePath (getSharedCodePath (config), RelativePath::buildTargetFolder).getParentDirectory().toUnixStyle().quoted()); return librarySearchPaths; @@ -601,7 +601,7 @@ private: xml.createNewChildElement ("Option")->setAttribute ("type", getTypeIndex (target.type)); xml.createNewChildElement ("Option")->setAttribute ("compiler", "gcc"); - if (getProject().getProjectType().isAudioPlugin() && target.type != ProjectType::Target::SharedCodeTarget) + if (getProject().isAudioPluginProject() && target.type != ProjectType::Target::SharedCodeTarget) xml.createNewChildElement ("Option")->setAttribute ("external_deps", getSharedCodePath (config)); { @@ -635,7 +635,7 @@ private: { auto* linker = xml.createNewChildElement ("Linker"); - if (getProject().getProjectType().isAudioPlugin() && target.type != ProjectType::Target::SharedCodeTarget) + if (getProject().isAudioPluginProject() && target.type != ProjectType::Target::SharedCodeTarget) setAddOption (*linker, "option", getSharedCodePath (config).quoted()); for (auto& flag : getLinkerFlags (config, target)) @@ -747,7 +747,7 @@ private: // the single target CodeBlocksTarget& getMainTarget() const { - if (getProject().getProjectType().isAudioPlugin()) + if (getProject().isAudioPluginProject()) return getTargetWithType (ProjectType::Target::SharedCodeTarget); for (auto* target : targets) @@ -761,7 +761,7 @@ private: CodeBlocksTarget& getTargetForProjectItem (const Project::Item& projectItem) const { - if (getProject().getProjectType().isAudioPlugin()) + if (getProject().isAudioPluginProject()) { if (! projectItem.shouldBeCompiled()) return getTargetWithType (ProjectType::Target::SharedCodeTarget); diff --git a/extras/Projucer/Source/ProjectSaving/jucer_ProjectExport_MSVC.h b/extras/Projucer/Source/ProjectSaving/jucer_ProjectExport_MSVC.h index f47c1331..bf46cb1f 100644 --- a/extras/Projucer/Source/ProjectSaving/jucer_ProjectExport_MSVC.h +++ b/extras/Projucer/Source/ProjectSaving/jucer_ProjectExport_MSVC.h @@ -196,7 +196,8 @@ public: void createConfigProperties (PropertyListBuilder& props) override { - addVisualStudioPluginInstallPathProperties (props); + if (project.isAudioPluginProject()) + addVisualStudioPluginInstallPathProperties (props); props.add (new ChoicePropertyComponent (architectureTypeValue, "Architecture", { get32BitArchName(), get64BitArchName() }, @@ -741,7 +742,7 @@ public: //============================================================================== void addFilesToCompile (const Project::Item& projectItem, XmlElement& cpps, XmlElement& headers, XmlElement& otherFiles) const { - auto targetType = (getOwner().getProject().getProjectType().isAudioPlugin() ? type : SharedCodeTarget); + auto targetType = (getOwner().getProject().isAudioPluginProject() ? type : SharedCodeTarget); if (projectItem.isGroup()) { @@ -823,7 +824,7 @@ public: bool addFilesToFilter (const Project::Item& projectItem, const String& path, XmlElement& cpps, XmlElement& headers, XmlElement& otherFiles, XmlElement& groups) const { - auto targetType = (getOwner().getProject().getProjectType().isAudioPlugin() ? type : SharedCodeTarget); + auto targetType = (getOwner().getProject().isAudioPluginProject() ? type : SharedCodeTarget); if (projectItem.isGroup()) { @@ -1133,7 +1134,7 @@ public: String getPostBuildSteps (const MSVCBuildConfiguration& config) const { - auto postBuild = config.getPostbuildCommandString(); + auto postBuild = config.getPostbuildCommandString().replace ("\n", "\r\n");; auto extraPostBuild = getExtraPostBuildSteps (config); return postBuild + String (postBuild.isNotEmpty() && extraPostBuild.isNotEmpty() ? "\r\n" : "") + extraPostBuild; @@ -1141,7 +1142,7 @@ public: String getPreBuildSteps (const MSVCBuildConfiguration& config) const { - auto preBuild = config.getPrebuildCommandString(); + auto preBuild = config.getPrebuildCommandString().replace ("\n", "\r\n");; auto extraPreBuild = getExtraPreBuildSteps (config); return preBuild + String (preBuild.isNotEmpty() && extraPreBuild.isNotEmpty() ? "\r\n" : "") + extraPreBuild; diff --git a/extras/Projucer/Source/ProjectSaving/jucer_ProjectExport_Make.h b/extras/Projucer/Source/ProjectSaving/jucer_ProjectExport_Make.h index 88fd4f1e..02e4b223 100644 --- a/extras/Projucer/Source/ProjectSaving/jucer_ProjectExport_Make.h +++ b/extras/Projucer/Source/ProjectSaving/jucer_ProjectExport_Make.h @@ -718,7 +718,7 @@ private: } else { - if (! getProject().getProjectType().isAudioPlugin()) + if (! getProject().isAudioPluginProject()) out << "all : " << target->getBuildProduct() << newLine << newLine; target->writeTargetLine (out, packages); @@ -903,7 +903,7 @@ private: { Array> targetFiles; - auto targetType = (p.getProjectType().isAudioPlugin() ? target->type : MakefileTarget::SharedCodeTarget); + auto targetType = (p.isAudioPluginProject() ? target->type : MakefileTarget::SharedCodeTarget); for (auto& f : files) if (p.getTargetTypeFromFilePath (f.first, true) == targetType) @@ -955,7 +955,7 @@ private: phonyTargetLine << ".PHONY: clean all strip"; - if (! getProject().getProjectType().isAudioPlugin()) + if (! getProject().isAudioPluginProject()) return phonyTargetLine.toString(); for (auto target : targets) diff --git a/extras/Projucer/Source/ProjectSaving/jucer_ProjectExport_Xcode.h b/extras/Projucer/Source/ProjectSaving/jucer_ProjectExport_Xcode.h index 1764dcaa..1331222d 100644 --- a/extras/Projucer/Source/ProjectSaving/jucer_ProjectExport_Xcode.h +++ b/extras/Projucer/Source/ProjectSaving/jucer_ProjectExport_Xcode.h @@ -46,6 +46,15 @@ namespace static String getSDKDisplayName (int version) { return getVersionName (version) + " SDK"; } static String getSDKRootName (int version) { return "macosx" + getVersionName (version); } + static String getOSXSDKVersion (const String& sdkVersion) + { + for (int v = oldestSDKVersion; v <= currentSDKVersion; ++v) + if (sdkVersion == getSDKDisplayName (v)) + return getSDKRootName (v); + + return "macosx"; + } + template static ContainerType getSDKChoiceList (int oldestVersion, bool displayName) { @@ -95,6 +104,7 @@ public: customXcodeResourceFoldersValue (settings, Ids::customXcodeResourceFolders, getUndoManager()), customXcassetsFolderValue (settings, Ids::customXcassetsFolder, getUndoManager()), appSandboxValue (settings, Ids::appSandbox, getUndoManager()), + appSandboxInheritanceValue (settings, Ids::appSandboxInheritance, getUndoManager()), appSandboxOptionsValue (settings, Ids::appSandboxOptions, getUndoManager(), Array(), ","), hardenedRuntimeValue (settings, Ids::hardenedRuntime, getUndoManager()), hardenedRuntimeOptionsValue (settings, Ids::hardenedRuntimeOptions, getUndoManager(), Array(), ","), @@ -168,6 +178,7 @@ public: Array getHardenedRuntimeOptions() const { return *hardenedRuntimeOptionsValue.get().getArray(); } bool isAppSandboxEnabled() const { return appSandboxValue.get(); } + bool isAppSandboxInhertianceEnabled() const { return appSandboxInheritanceValue.get(); } Array getAppSandboxOptions() const { return *appSandboxOptionsValue.get().getArray(); } bool isMicrophonePermissionEnabled() const { return microphonePermissionNeededValue.get(); } @@ -264,7 +275,7 @@ public: "This way you can specify them for OS X and iOS separately, and modify the content of the resource folders " "without re-saving the Projucer project."); - if (getProject().getProjectType().isAudioPlugin()) + if (getProject().isAudioPluginProject()) props.add (new ChoicePropertyComponent (duplicateAppExResourcesFolderValue, "Add Duplicate Resources Folder to App Extension"), "Disable this to prevent the Projucer from creating a duplicate resources folder for AUv3 app extensions."); @@ -309,6 +320,11 @@ public: props.add (new ChoicePropertyComponent (appSandboxValue, "Use App Sandbox"), "Enable this to use the app sandbox."); + props.add (new ChoicePropertyComponentWithEnablement (appSandboxInheritanceValue, appSandboxValue, "App Sandbox Inheritance"), + "If app sandbox is enabled, this setting will configure a child process to inherit the sandbox of its parent. " + "Note that if you enable this and have specified any other app sandbox entitlements below, the child process " + "will fail to launch."); + std::vector> sandboxOptions { { "Network: Incoming Connections (Server)", "network.server" }, @@ -333,7 +349,18 @@ public: { "File Access: Music Folder (Read Only)", "assets.music.read-only" }, { "File Access: Music Folder (Read/Write)", "assets.music.read-write" }, { "File Access: Movies Folder (Read Only)", "assets.movies.read-only" }, - { "File Access: Movies Folder (Read/Write)", "assets.movies.read-write" } + { "File Access: Movies Folder (Read/Write)", "assets.movies.read-write" }, + + { "Temporary Exception: Audio Unit Hosting", "temporary-exception.audio-unit-host" }, + { "Temporary Exception: Global Mach Service", "temporary-exception.mach-lookup.global-name" }, + { "Temporary Exception: Global Mach Service Dynamic Registration", "temporary-exception.mach-register.global-name" }, + { "Temporary Exception: Home Directory File Access (Read Only)", "temporary-exception.files.home-relative-path.read-only" }, + { "Temporary Exception: Home Directory File Access (Read/Write)", "temporary-exception.files.home-relative-path.read-write" }, + { "Temporary Exception: Absolute Path File Access (Read Only)", "temporary-exception.files.absolute-path.read-only" }, + { "Temporary Exception: Absolute Path File Access (Read/Write)", "temporary-exception.files.absolute-path.read-write" }, + { "Temporary Exception: IOKit User Client Class", "temporary-exception.iokit-user-client-class" }, + { "Temporary Exception: Shared Preference Domain (Read Only)", "temporary-exception.shared-preference.read-only" }, + { "Temporary Exception: Shared Preference Domain (Read/Write)", "temporary-exception.shared-preference.read-write" } }; StringArray sandboxKeys; @@ -470,7 +497,7 @@ public: props.add (new TextPropertyComponent (subprojectsValue, "Xcode Subprojects", 8192, true), "Paths to Xcode projects that should be added to the build (one per line). " - "The names of the required build products can be specified after a colon, comma seperated, " + "The names of the required build products can be specified after a colon, comma separated, " "e.g. \"path/to/MySubProject.xcodeproj: MySubProject, OtherTarget\". " "If no build products are specified, all build products associated with a subproject will be added."); @@ -647,7 +674,9 @@ protected: //============================================================================== void createConfigProperties (PropertyListBuilder& props) override { - addXcodePluginInstallPathProperties (props); + if (project.isAudioPluginProject()) + addXcodePluginInstallPathProperties (props); + addRecommendedLLVMCompilerWarningsProperty (props); addGCCOptimisationProperty (props); @@ -665,8 +694,7 @@ protected: { props.add (new ChoicePropertyComponent (osxSDKVersion, "OSX Base SDK Version", getSDKChoiceList (oldestSDKVersion, true), getSDKChoiceList> (oldestSDKVersion, true)), - "The version of OSX to link against in the Xcode build. If \"Default\" is selected then the field will be left " - "empty and the Xcode default will be used."); + "The version of the macOS SDK to link against. If \"Default\" is selected then the Xcode default will be used."); props.add (new ChoicePropertyComponent (osxDeploymentTarget, "OSX Deployment Target", getSDKChoiceList (oldestDeploymentTarget, false), getSDKChoiceList> (oldestDeploymentTarget, true)), @@ -693,7 +721,10 @@ protected: props.add (new ChoicePropertyComponent (stripLocalSymbolsEnabled, "Strip Local Symbols"), "Enable this to strip any locally defined symbols resulting in a smaller binary size. Enabling this " - "will also remove any function names from crash logs. Must be disabled for static library projects."); + "will also remove any function names from crash logs. Must be disabled for static library projects. " + "Note that disabling this will not necessarily generate full debug symbols. For release configs, " + "you will also need to add the following to the \"Custom Xcode Flags\" field: " + "GCC_GENERATE_DEBUGGING_SYMBOLS = YES, STRIP_INSTALLED_PRODUCT = NO, COPY_PHASE_STRIP = NO"); } String getModuleLibraryArchName() const override @@ -968,6 +999,11 @@ public: return String ("Info-") + String (getName()).replace (" ", "_") + String (".plist"); } + String getEntitlementsFilename() const + { + return String (getName()).replace (" ", "_") + String (".entitlements"); + } + String xcodePackageType, xcodeBundleSignature, xcodeBundleExtension; String xcodeProductType, xcodeFileType; String xcodeOtherRezFlags, xcodeBundleIDSubPath; @@ -990,7 +1026,7 @@ public: { Array result; - auto targetType = (owner.getProject().getProjectType().isAudioPlugin() ? type : SharedCodeTarget); + auto targetType = (owner.getProject().isAudioPluginProject() ? type : SharedCodeTarget); if (projectItem.isGroup()) { @@ -1161,8 +1197,8 @@ public: || (owner.isiOS() && owner.isiCloudPermissionsEnabled())) return true; - if (owner.project.getProjectType().isAudioPlugin() - && ( (owner.isOSX() && type == Target::AudioUnitv3PlugIn) + if (owner.project.isAudioPluginProject() + && ((owner.isOSX() && type == Target::AudioUnitv3PlugIn) || (owner.isiOS() && type == Target::StandalonePlugIn && owner.getProject().shouldEnableIAA()))) return true; @@ -1196,11 +1232,7 @@ public: // the aggregate target needs to have the deployment target set for // pre-/post-build scripts s.set ("MACOSX_DEPLOYMENT_TARGET", getOSXDeploymentTarget (config.getOSXDeploymentTargetString())); - - auto sdkRoot = getOSXSDKVersion (config.getOSXSDKVersionString()); - - if (sdkRoot.isNotEmpty()) - s.set ("SDKROOT", sdkRoot); + s.set ("SDKROOT", getOSXSDKVersion (config.getOSXSDKVersionString())); return s; } @@ -1331,11 +1363,6 @@ public: else { s.set ("MACOSX_DEPLOYMENT_TARGET", getOSXDeploymentTarget (config.getOSXDeploymentTargetString())); - - auto sdkRoot = getOSXSDKVersion (config.getOSXSDKVersionString()); - - if (sdkRoot.isNotEmpty()) - s.set ("SDKROOT", sdkRoot); } s.set ("GCC_VERSION", gccVersion); @@ -1352,7 +1379,7 @@ public: s.set ("DEVELOPMENT_TEAM", owner.getDevelopmentTeamIDString()); if (shouldAddEntitlements()) - s.set ("CODE_SIGN_ENTITLEMENTS", owner.getEntitlementsFileName().quoted()); + s.set ("CODE_SIGN_ENTITLEMENTS", getEntitlementsFilename().quoted()); { auto cppStandard = owner.project.getCppStandardString(); @@ -1487,7 +1514,7 @@ public: librarySearchPaths.add (owner.getSearchPathForStaticLibrary (lib)); } - if (owner.project.getProjectType().isAudioPlugin()) + if (owner.project.isAudioPluginProject()) { if (owner.getTargetOfType (Target::SharedCodeTarget) != nullptr) { @@ -1768,7 +1795,7 @@ public: " -I \\\"$(DEVELOPER_DIR)/Extras/CoreAudio/AudioUnits/AUPublic/AUBase\\\"" " -I \\\"$(DEVELOPER_DIR)/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/System/Library/Frameworks/AudioUnit.framework/Headers\\\""; - xcodeFrameworks.addTokens ("AudioUnit CoreAudioKit", false); + xcodeFrameworks.addArray ({ "AudioUnit", "CoreAudioKit" }); XmlElement plistKey ("key"); plistKey.addTextElement ("AudioComponents"); @@ -1815,10 +1842,10 @@ public: void addExtraAudioUnitv3PlugInTargetSettings() { - if (owner.isiOS()) - xcodeFrameworks.addTokens ("CoreAudioKit AVFoundation", false); - else - xcodeFrameworks.addTokens ("AudioUnit CoreAudioKit AVFoundation", false); + xcodeFrameworks.addArray ({ "AVFoundation", "CoreAudioKit" }); + + if (owner.isOSX()) + xcodeFrameworks.add ("AudioUnit"); XmlElement plistKey ("key"); plistKey.addTextElement ("NSExtension"); @@ -1934,15 +1961,6 @@ public: return getVersionName (minVersion); } - String getOSXSDKVersion (const String& sdkVersion) const - { - for (int v = oldestSDKVersion; v <= currentSDKVersion; ++v) - if (sdkVersion == getSDKDisplayName (v)) - return getSDKRootName (v); - - return {}; - } - //============================================================================== const XcodeProjectExporter& owner; @@ -1974,7 +1992,7 @@ private: postbuildCommandValue, prebuildCommandValue, duplicateAppExResourcesFolderValue, iosDeviceFamilyValue, iPhoneScreenOrientationValue, iPadScreenOrientationValue, customXcodeResourceFoldersValue, customXcassetsFolderValue, - appSandboxValue, appSandboxOptionsValue, + appSandboxValue, appSandboxInheritanceValue, appSandboxOptionsValue, hardenedRuntimeValue, hardenedRuntimeOptionsValue, microphonePermissionNeededValue, microphonePermissionsTextValue, cameraPermissionNeededValue, cameraPermissionTextValue, iosBluetoothPermissionNeededValue, iosBluetoothPermissionTextValue, uiFileSharingEnabledValue, uiSupportsDocumentBrowserValue, uiStatusBarHiddenValue, documentExtensionsValue, iosInAppPurchasesValue, @@ -2133,7 +2151,8 @@ private: void addFilesAndGroupsToProject (StringArray& topLevelGroupIDs) const { - addEntitlementsFile(); + for (auto* target : targets) + addEntitlementsFile (*target); for (auto& group : getAllGroups()) { @@ -2216,7 +2235,7 @@ private: auto sourceFiles = target->sourceIDs; if (target->type == XcodeTarget::SharedCodeTarget - || (! project.getProjectType().isAudioPlugin())) + || (! project.isAudioPluginProject())) sourceFiles.addArray (sourceIDs); target->addBuildPhase ("PBXSourcesBuildPhase", sourceFiles); @@ -2227,11 +2246,11 @@ private: target->addShellScriptBuildPhase ("Post-build script", getPostBuildScript()); - if (project.getProjectType().isAudioPlugin() && project.shouldBuildAUv3() + if (project.isAudioPluginProject() && project.shouldBuildAUv3() && project.shouldBuildStandalonePlugin() && target->type == XcodeTarget::StandalonePlugIn) embedAppExtension(); - if (project.getProjectType().isAudioPlugin() && project.shouldBuildUnityPlugin() + if (project.isAudioPluginProject() && project.shouldBuildUnityPlugin() && target->type == XcodeTarget::UnityPlugIn) embedUnityScript(); @@ -2338,7 +2357,7 @@ private: { StringArray dependencies; - if (project.getProjectType().isAudioPlugin()) + if (project.isAudioPluginProject()) { if (target.type == XcodeTarget::StandalonePlugIn) // depends on AUv3 and shared code { @@ -2617,6 +2636,10 @@ private: s.set ("TARGETED_DEVICE_FAMILY", getDeviceFamilyString().quoted()); s.set ("IPHONEOS_DEPLOYMENT_TARGET", config.getiOSDeploymentTargetString()); } + else + { + s.set ("SDKROOT", getOSXSDKVersion (config.getOSXSDKVersionString())); + } s.set ("ZERO_LINK", "NO"); @@ -2656,6 +2679,16 @@ private: s.removeDuplicates (true); s.sort (true); + // When building against the 10.15 SDK we need to make sure the + // AudioUnit framework is linked before the AudioToolbox framework. + auto audioUnitIndex = s.indexOf ("AudioUnit", false, 1); + + if (audioUnitIndex != -1) + { + s.remove (audioUnitIndex); + s.insert (0, "AudioUnit"); + } + for (auto& framework : s) { auto frameworkID = addFramework (framework); @@ -3079,26 +3112,14 @@ private: return {}; } - String getEntitlementsFileName() const - { - return project.getProjectFilenameRootString() + String (".entitlements"); - } - - StringPairArray getEntitlements() const + StringPairArray getEntitlements (XcodeTarget& target) const { StringPairArray entitlements; - if (project.getProjectType().isAudioPlugin()) + if (project.isAudioPluginProject()) { - if (isiOS()) - { - if (project.shouldEnableIAA()) - entitlements.set ("inter-app-audio", ""); - } - else - { - entitlements.set ("com.apple.security.app-sandbox", ""); - } + if (isiOS() && project.shouldEnableIAA()) + entitlements.set ("inter-app-audio", ""); } else { @@ -3125,9 +3146,22 @@ private: for (auto& option : getHardenedRuntimeOptions()) entitlements.set (option, ""); - if (isAppSandboxEnabled()) - for (auto& option : getAppSandboxOptions()) - entitlements.set (option, ""); + if (isAppSandboxEnabled() || (project.isAudioPluginProject() && target.type == XcodeTarget::AudioUnitv3PlugIn)) + { + entitlements.set ("com.apple.security.app-sandbox", ""); + + if (isAppSandboxInhertianceEnabled()) + { + // no other sandbox options can be specified if sandbox inheritance is enabled! + jassert (getAppSandboxOptions().isEmpty()); + + entitlements.set ("com.apple.security.inherit", ""); + } + + if (isAppSandboxEnabled()) + for (auto& option : getAppSandboxOptions()) + entitlements.set (option, ""); + } if (isiOS() && isiCloudPermissionsEnabled()) { @@ -3150,30 +3184,31 @@ private: return entitlements; } - String addEntitlementsFile() const + void addEntitlementsFile (XcodeTarget& target) const { - String content = - "\n" - "\n" - "\n" - "\n"; - - auto entitlements = getEntitlements(); - auto keys = entitlements.getAllKeys(); + auto entitlements = getEntitlements (target); - for (auto& key : keys) + if (entitlements.size() > 0) { - content += "\t" + key + "\n" - "\t" + entitlements[key] + "\n"; - } - content += "\n" - "\n"; + String content = + "\n" + "\n" + "\n" + "\n"; - auto entitlementsFile = getTargetFolder().getChildFile (getEntitlementsFileName()); - overwriteFileIfDifferentOrThrow (entitlementsFile, content); + for (auto& key : entitlements.getAllKeys()) + content += "\t" + key + "\n" + "\t" + entitlements[key] + "\n"; - RelativePath plistPath (entitlementsFile, getTargetFolder(), RelativePath::buildTargetFolder); - return addFile (plistPath, false, false, false, false, nullptr, {}); + content += "\n" + "\n"; + + auto entitlementsFile = getTargetFolder().getChildFile (target.getEntitlementsFilename()); + overwriteFileIfDifferentOrThrow (entitlementsFile, content); + + RelativePath entitlementsPath (entitlementsFile, getTargetFolder(), RelativePath::buildTargetFolder); + addFile (entitlementsPath, false, false, false, false, nullptr, {}); + } } String addProjectItem (const Project::Item& projectItem) const diff --git a/extras/Projucer/Source/ProjectSaving/jucer_ProjectSaver.h b/extras/Projucer/Source/ProjectSaving/jucer_ProjectSaver.h index c2711ecc..ec3ae4a0 100644 --- a/extras/Projucer/Source/ProjectSaving/jucer_ProjectSaver.h +++ b/extras/Projucer/Source/ProjectSaving/jucer_ProjectSaver.h @@ -95,7 +95,7 @@ public: auto projectRootHash = project.getProjectRoot().toXmlString().hashCode(); - if (project.getProjectType().isAudioPlugin()) + if (project.isAudioPluginProject()) { writePluginCharacteristicsFile(); @@ -125,7 +125,7 @@ public: if (errors.size() == 0) { - // Workaround for a bug where Xcode thinks the project is invalid if opened immedietely + // Workaround for a bug where Xcode thinks the project is invalid if opened immediately // after writing if (waitAfterSaving) Thread::sleep (2000); @@ -157,7 +157,7 @@ public: if (errors.size() == 0) { - if (project.getProjectType().isAudioPlugin()) + if (project.isAudioPluginProject()) writePluginCharacteristicsFile(); writeAppConfigFile (modules, loadUserContentFromAppConfig()); @@ -348,7 +348,7 @@ private: return longest; } - File getAppConfigFile() const { return generatedCodeFolder.getChildFile (project.getAppConfigFilename()); } + File getAppConfigFile() const { return generatedCodeFolder.getChildFile (Project::getAppConfigFilename()); } String loadUserContentFromAppConfig() const { @@ -525,7 +525,7 @@ private: mem.setNewLineString (projectLineFeed); writeAppConfig (mem, modules, userContent); - saveGeneratedFile (project.getAppConfigFilename(), mem); + saveGeneratedFile (Project::getAppConfigFilename(), mem); } void writeAppHeader (MemoryOutputStream& out, const OwnedArray& modules) @@ -542,7 +542,7 @@ private: out << "#pragma once" << newLine << newLine; if (appConfigFile.exists()) - out << CodeHelpers::createIncludeStatement (project.getAppConfigFilename()) << newLine; + out << CodeHelpers::createIncludeStatement (Project::getAppConfigFilename()) << newLine; if (modules.size() > 0) { @@ -590,7 +590,7 @@ private: mem.setNewLineString (projectLineFeed); writeAppHeader (mem, modules); - saveGeneratedFile (project.getJuceSourceHFilename(), mem); + saveGeneratedFile (Project::getJuceSourceHFilename(), mem); } void writeModuleCppWrappers (const OwnedArray& modules) @@ -606,7 +606,7 @@ private: mem << "*/" << newLine << newLine - << "#include " << project.getAppConfigFilename().quoted() << newLine + << "#include " << Project::getAppConfigFilename().quoted() << newLine << "#include <"; if (cu.file.getFileExtension() != ".r") // .r files are included without the path diff --git a/extras/Projucer/Source/Settings/jucer_StoredSettings.cpp b/extras/Projucer/Source/Settings/jucer_StoredSettings.cpp index 08da017a..74f751e7 100644 --- a/extras/Projucer/Source/Settings/jucer_StoredSettings.cpp +++ b/extras/Projucer/Source/Settings/jucer_StoredSettings.cpp @@ -409,12 +409,16 @@ static String getFallbackPathForOS (const Identifier& key, DependencyPathOS os) } else if (key == Ids::androidSDKPath) { - return (os == TargetOS::linux ? "${user.home}/Android/Sdk" : - "${user.home}/Library/Android/sdk"); + if (os == TargetOS::windows) return "${user.home}\\AppData\\Local\\Android\\Sdk"; + else if (os == TargetOS::osx) return "${user.home}/Library/Android/sdk"; + else if (os == TargetOS::linux) return "${user.home}/Android/Sdk"; + + jassertfalse; + return {}; } else if (key == Ids::androidNDKPath) { - return getFallbackPathForOS (Ids::androidSDKPath, os) + "/ndk-bundle"; + return getFallbackPathForOS (Ids::androidSDKPath, os) + File::getSeparatorChar() + "ndk-bundle"; } else if (key == Ids::clionExePath) { diff --git a/extras/Projucer/Source/Utility/Helpers/jucer_CodeHelpers.cpp b/extras/Projucer/Source/Utility/Helpers/jucer_CodeHelpers.cpp index bf7af246..18a1a799 100644 --- a/extras/Projucer/Source/Utility/Helpers/jucer_CodeHelpers.cpp +++ b/extras/Projucer/Source/Utility/Helpers/jucer_CodeHelpers.cpp @@ -135,6 +135,11 @@ namespace CodeHelpers return "#include \"" + includePath + "\""; } + String createIncludePathIncludeStatement (const String& includedFilename) + { + return "#include <" + includedFilename + ">"; + } + String makeBinaryDataIdentifierName (const File& file) { return makeValidIdentifier (file.getFileName() diff --git a/extras/Projucer/Source/Utility/Helpers/jucer_CodeHelpers.h b/extras/Projucer/Source/Utility/Helpers/jucer_CodeHelpers.h index d348f836..5947e083 100644 --- a/extras/Projucer/Source/Utility/Helpers/jucer_CodeHelpers.h +++ b/extras/Projucer/Source/Utility/Helpers/jucer_CodeHelpers.h @@ -34,9 +34,11 @@ namespace CodeHelpers String unindent (const String& code, int numSpaces); String makeValidIdentifier (String s, bool capitalise, bool removeColons, bool allowTemplates, bool allowAsterisks = false); + String makeBinaryDataIdentifierName (const File& file); + String createIncludeStatement (const File& includedFile, const File& targetFile); String createIncludeStatement (const String& includePath); - String makeBinaryDataIdentifierName (const File& file); + String createIncludePathIncludeStatement (const String& includedFilename); String stringLiteral (const String& text, int maxLineLength = -1); String floatLiteral (double value, int numDecPlaces); diff --git a/extras/Projucer/Source/Utility/Helpers/jucer_PresetIDs.h b/extras/Projucer/Source/Utility/Helpers/jucer_PresetIDs.h index 5a3ef9cb..54012f3f 100644 --- a/extras/Projucer/Source/Utility/Helpers/jucer_PresetIDs.h +++ b/extras/Projucer/Source/Utility/Helpers/jucer_PresetIDs.h @@ -187,6 +187,7 @@ namespace Ids DECLARE_ID (useLocalCopy); DECLARE_ID (overwriteOnSave); DECLARE_ID (appSandbox); + DECLARE_ID (appSandboxInheritance); DECLARE_ID (appSandboxOptions); DECLARE_ID (hardenedRuntime); DECLARE_ID (hardenedRuntimeOptions); diff --git a/extras/Projucer/Source/Utility/Helpers/jucer_VersionInfo.cpp b/extras/Projucer/Source/Utility/Helpers/jucer_VersionInfo.cpp new file mode 100644 index 00000000..63cefab1 --- /dev/null +++ b/extras/Projucer/Source/Utility/Helpers/jucer_VersionInfo.cpp @@ -0,0 +1,115 @@ +/* + ============================================================================== + + This file is part of the JUCE library. + Copyright (c) 2017 - ROLI Ltd. + + JUCE is an open source library subject to commercial or open-source + licensing. + + By using JUCE, you agree to the terms of both the JUCE 5 End-User License + Agreement and JUCE 5 Privacy Policy (both updated and effective as of the + 27th April 2017). + + End User License Agreement: www.juce.com/juce-5-licence + Privacy Policy: www.juce.com/juce-5-privacy-policy + + Or: You may also use this code under the terms of the GPL v3 (see + www.gnu.org/licenses). + + JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER + EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE + DISCLAIMED. + + ============================================================================== +*/ + +#include "../../Application/jucer_Headers.h" +#include "jucer_VersionInfo.h" + +std::unique_ptr VersionInfo::fetchFromUpdateServer (const String& versionString) +{ + return fetch ("tags/" + versionString); +} + +std::unique_ptr VersionInfo::fetchLatestFromUpdateServer() +{ + return fetch ("latest"); +} + +std::unique_ptr VersionInfo::createInputStreamForAsset (const Asset& asset, int& statusCode) +{ + URL downloadUrl (asset.url); + StringPairArray responseHeaders; + + return std::unique_ptr (downloadUrl.createInputStream (false, nullptr, nullptr, + "Accept: application/octet-stream", + 0, &responseHeaders, &statusCode, 1)); +} + +bool VersionInfo::isNewerVersionThanCurrent() +{ + jassert (versionString.isNotEmpty()); + + auto currentTokens = StringArray::fromTokens (ProjectInfo::versionString, ".", {}); + auto thisTokens = StringArray::fromTokens (versionString, ".", {}); + + jassert (thisTokens.size() == 3 && thisTokens.size() == 3); + + if (currentTokens[0].getIntValue() == thisTokens[0].getIntValue()) + { + if (currentTokens[1].getIntValue() == thisTokens[1].getIntValue()) + return currentTokens[2].getIntValue() < thisTokens[2].getIntValue(); + + return currentTokens[1].getIntValue() < thisTokens[1].getIntValue(); + } + + return currentTokens[0].getIntValue() < thisTokens[0].getIntValue(); +} + +std::unique_ptr VersionInfo::fetch (const String& endpoint) +{ + URL latestVersionURL ("https://api.github.com/repos/WeAreROLI/JUCE/releases/" + endpoint); + std::unique_ptr inStream (latestVersionURL.createInputStream (false)); + + if (inStream == nullptr) + return nullptr; + + auto content = inStream->readEntireStreamAsString(); + auto latestReleaseDetails = JSON::parse (content); + + auto* json = latestReleaseDetails.getDynamicObject(); + + if (json == nullptr) + return nullptr; + + auto versionString = json->getProperty ("tag_name").toString(); + + if (versionString.isEmpty()) + return nullptr; + + auto* assets = json->getProperty ("assets").getArray(); + + if (assets == nullptr) + return nullptr; + + auto releaseNotes = json->getProperty ("body").toString(); + std::vector parsedAssets; + + for (auto& asset : *assets) + { + if (auto* assetJson = asset.getDynamicObject()) + { + parsedAssets.push_back ({ assetJson->getProperty ("name").toString(), + assetJson->getProperty ("url").toString() }); + jassert (parsedAssets.back().name.isNotEmpty()); + jassert (parsedAssets.back().url.isNotEmpty()); + } + else + { + jassertfalse; + } + } + + return std::unique_ptr (new VersionInfo ({ versionString, releaseNotes, std::move (parsedAssets) })); +} diff --git a/extras/Projucer/Source/Utility/Helpers/jucer_VersionInfo.h b/extras/Projucer/Source/Utility/Helpers/jucer_VersionInfo.h new file mode 100644 index 00000000..68ec8e71 --- /dev/null +++ b/extras/Projucer/Source/Utility/Helpers/jucer_VersionInfo.h @@ -0,0 +1,54 @@ +/* + ============================================================================== + + This file is part of the JUCE library. + Copyright (c) 2017 - ROLI Ltd. + + JUCE is an open source library subject to commercial or open-source + licensing. + + By using JUCE, you agree to the terms of both the JUCE 5 End-User License + Agreement and JUCE 5 Privacy Policy (both updated and effective as of the + 27th April 2017). + + End User License Agreement: www.juce.com/juce-5-licence + Privacy Policy: www.juce.com/juce-5-privacy-policy + + Or: You may also use this code under the terms of the GPL v3 (see + www.gnu.org/licenses). + + JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER + EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE + DISCLAIMED. + + ============================================================================== +*/ + +#pragma once + + +//============================================================================== +class VersionInfo +{ +public: + struct Asset + { + const String name; + const String url; + }; + + static std::unique_ptr fetchFromUpdateServer (const String& versionString); + static std::unique_ptr fetchLatestFromUpdateServer(); + static std::unique_ptr createInputStreamForAsset (const Asset& asset, int& statusCode); + + bool isNewerVersionThanCurrent(); + + const String versionString; + const String releaseNotes; + const std::vector assets; + +private: + VersionInfo() = default; + + static std::unique_ptr fetch (const String&); +}; diff --git a/extras/Projucer/Source/Utility/PIPs/jucer_PIPGenerator.cpp b/extras/Projucer/Source/Utility/PIPs/jucer_PIPGenerator.cpp index 483ad06d..6e219fe6 100644 --- a/extras/Projucer/Source/Utility/PIPs/jucer_PIPGenerator.cpp +++ b/extras/Projucer/Source/Utility/PIPs/jucer_PIPGenerator.cpp @@ -425,10 +425,16 @@ String PIPGenerator::getMainFileTextForType() { String mainTemplate (BinaryData::jucer_PIPMain_cpp); - mainTemplate = mainTemplate.replace ("%%filename%%", useLocalCopy ? pipFile.getFileName() - : isTemp ? pipFile.getFullPathName() - : RelativePath (pipFile, outputDirectory.getChildFile ("Source"), - RelativePath::unknown).toUnixStyle()); + auto includeFilename = [&] + { + if (useLocalCopy) return pipFile.getFileName(); + if (isTemp) return pipFile.getFullPathName(); + + return RelativePath (pipFile, outputDirectory.getChildFile ("Source"), RelativePath::unknown).toUnixStyle(); + }(); + + mainTemplate = mainTemplate.replace ("%%filename%%", includeFilename) + .replace ("%%include_juce%%", CodeHelpers::createIncludePathIncludeStatement (Project::getJuceSourceHFilename())); auto type = metadata[Ids::type].toString(); diff --git a/extras/Projucer/Source/Utility/UI/PropertyComponents/jucer_FilePathPropertyComponent.h b/extras/Projucer/Source/Utility/UI/PropertyComponents/jucer_FilePathPropertyComponent.h index ed558a21..bda4a63a 100644 --- a/extras/Projucer/Source/Utility/UI/PropertyComponents/jucer_FilePathPropertyComponent.h +++ b/extras/Projucer/Source/Utility/UI/PropertyComponents/jucer_FilePathPropertyComponent.h @@ -39,25 +39,23 @@ class FilePathPropertyComponent : public PropertyComponent, { public: FilePathPropertyComponent (Value valueToControl, const String& propertyName, bool isDir, bool thisOS = true, - const String& wildcardsToUse = "*", const File& relativeRoot = File(), bool multiPath = false) + const String& wildcardsToUse = "*", const File& relativeRoot = File()) : PropertyComponent (propertyName), text (valueToControl, propertyName, 1024, false), - isDirectory (isDir), isThisOS (thisOS), supportsMultiplePaths (multiPath), wildcards (wildcardsToUse), root (relativeRoot) + isDirectory (isDir), isThisOS (thisOS), wildcards (wildcardsToUse), root (relativeRoot) { textValue.referTo (valueToControl); - init(); } /** Displays a default value when no value is specified by the user. */ FilePathPropertyComponent (ValueWithDefault& valueToControl, const String& propertyName, bool isDir, bool thisOS = true, - const String& wildcardsToUse = "*", const File& relativeRoot = File(), bool multiPath = false) + const String& wildcardsToUse = "*", const File& relativeRoot = File()) : PropertyComponent (propertyName), text (valueToControl, propertyName, 1024, false), - isDirectory (isDir), isThisOS (thisOS), supportsMultiplePaths (multiPath), wildcards (wildcardsToUse), root (relativeRoot) + isDirectory (isDir), isThisOS (thisOS), wildcards (wildcardsToUse), root (relativeRoot) { textValue = valueToControl.getPropertyAsValue(); - init(); } @@ -89,15 +87,8 @@ public: void filesDropped (const StringArray& selectedFiles, int, int) override { - if (supportsMultiplePaths) - { - for (auto& f : selectedFiles) - setTo (f); - } - else - { - setTo (selectedFiles[0]); - } + + setTo (selectedFiles[0]); highlightForDragAndDrop = false; repaint(); @@ -126,11 +117,6 @@ private: auto pathName = (root == File()) ? f.getFullPathName() : f.getRelativePathFrom (root); - auto currentPath = text.getText(); - - if (supportsMultiplePaths && currentPath.isNotEmpty()) - pathName = currentPath.trimCharactersAtEnd (" ;") + "; " + pathName; - text.setText (pathName); updateEditorColour(); } @@ -160,24 +146,24 @@ private: void updateEditorColour() { - if (supportsMultiplePaths || ! isThisOS) - return; - - text.setColour (TextPropertyComponent::textColourId, findColour (widgetTextColourId)); + if (isThisOS) + { + text.setColour (TextPropertyComponent::textColourId, findColour (widgetTextColourId)); - auto pathToCheck = text.getText(); + auto pathToCheck = text.getText(); - if (pathToCheck.isNotEmpty()) - { - pathToCheck.replace ("${user.home}", "~"); + if (pathToCheck.isNotEmpty()) + { + pathToCheck.replace ("${user.home}", "~"); - #if JUCE_WINDOWS - if (pathToCheck.startsWith ("~")) - pathToCheck = pathToCheck.replace ("~", File::getSpecialLocation (File::userHomeDirectory).getFullPathName()); - #endif + #if JUCE_WINDOWS + if (pathToCheck.startsWith ("~")) + pathToCheck = pathToCheck.replace ("~", File::getSpecialLocation (File::userHomeDirectory).getFullPathName()); + #endif - if (! root.getChildFile (pathToCheck).exists()) - text.setColour (TextPropertyComponent::textColourId, Colours::red); + if (! root.getChildFile (pathToCheck).exists()) + text.setColour (TextPropertyComponent::textColourId, Colours::red); + } } } @@ -200,7 +186,7 @@ private: TextPropertyComponent text; TextButton browseButton { "..." }; - bool isDirectory, isThisOS, supportsMultiplePaths, highlightForDragAndDrop = false; + bool isDirectory, isThisOS, highlightForDragAndDrop = false; String wildcards; File root; diff --git a/extras/Projucer/Source/Wizards/jucer_NewFileWizard.cpp b/extras/Projucer/Source/Wizards/jucer_NewFileWizard.cpp index 70a84940..83143003 100644 --- a/extras/Projucer/Source/Wizards/jucer_NewFileWizard.cpp +++ b/extras/Projucer/Source/Wizards/jucer_NewFileWizard.cpp @@ -170,7 +170,7 @@ public: { auto content = fillInBasicTemplateFields (newFile, parent, templateName) .replace ("%%component_class%%", className) - .replace ("%%include_juce%%", CodeHelpers::createIncludeStatement (parent.project.getAppIncludeFile(), newFile)); + .replace ("%%include_juce%%", CodeHelpers::createIncludePathIncludeStatement (Project::getJuceSourceHFilename())); content = replaceLineFeeds (content, parent.project.getProjectLineFeed()); diff --git a/extras/Projucer/Source/Wizards/jucer_NewProjectWizardComponent.h b/extras/Projucer/Source/Wizards/jucer_NewProjectWizardComponent.h index 9df14837..8c83da37 100644 --- a/extras/Projucer/Source/Wizards/jucer_NewProjectWizardComponent.h +++ b/extras/Projucer/Source/Wizards/jucer_NewProjectWizardComponent.h @@ -54,9 +54,7 @@ public: addAndMakeVisible (modulesLabel); modulesLabel.attachToComponent (¤tPathBox, true); - addAndMakeVisible (useGlobalPathsToggle); - useGlobalPathsToggle.setToggleState (true, sendNotification); - useGlobalPathsToggle.onClick = [this] + auto updateEnablement = [this] { isUsingGlobalPaths = useGlobalPathsToggle.getToggleState(); @@ -64,6 +62,12 @@ public: openFolderButton.setEnabled (! isUsingGlobalPaths); modulesLabel.setEnabled (! isUsingGlobalPaths); }; + + addAndMakeVisible (useGlobalPathsToggle); + useGlobalPathsToggle.setToggleState (true, sendNotification); + useGlobalPathsToggle.onClick = [updateEnablement] { updateEnablement(); }; + + updateEnablement(); } void resized() override @@ -419,7 +423,10 @@ public: return; if (modulesPathBox.isUsingGlobalPaths) + { getAppSettings().getStoredPath (Ids::defaultJuceModulePath, TargetOS::getThisOS()).setValue (wizard->modulesFolder.getFullPathName(), nullptr); + ProjucerApplication::getApp().rescanJUCEPathModules(); + } } auto projectDir = fileBrowser.getSelectedFile (0); @@ -429,7 +436,7 @@ public: if (project != nullptr) { - mw->setProject (project.release()); + mw->setProject (std::move (project)); getAppSettings().lastWizardFolder = projectDir.getParentDirectory(); } } diff --git a/extras/Projucer/Source/Wizards/jucer_ProjectWizard_Animated.h b/extras/Projucer/Source/Wizards/jucer_ProjectWizard_Animated.h index 6988b26b..5dbd0d38 100644 --- a/extras/Projucer/Source/Wizards/jucer_ProjectWizard_Animated.h +++ b/extras/Projucer/Source/Wizards/jucer_ProjectWizard_Animated.h @@ -71,14 +71,13 @@ struct AnimatedAppWizard : public NewProjectWizard setExecutableNameForAllTargets (project, File::createLegalFileName (appTitle)); - String appHeaders (CodeHelpers::createIncludeStatement (project.getAppIncludeFile(), mainCppFile)); + auto juceHeaderInclude = CodeHelpers::createIncludePathIncludeStatement (Project::getJuceSourceHFilename()); + auto appHeaders = juceHeaderInclude + newLine + CodeHelpers::createIncludeStatement (contentCompH, mainCppFile); // create main window - appHeaders << newLine << CodeHelpers::createIncludeStatement (contentCompH, mainCppFile); - String windowH = project.getFileTemplate (createCppFile ? "jucer_AnimatedComponentTemplate_h" : "jucer_AnimatedComponentSimpleTemplate_h") - .replace ("%%include_juce%%", CodeHelpers::createIncludeStatement (project.getAppIncludeFile(), contentCompH), false) + .replace ("%%include_juce%%", juceHeaderInclude) .replace ("%%content_component_class%%", contentCompName, false); if (! FileHelpers::overwriteFileWithNewDataIfDifferent (contentCompH, windowH)) @@ -89,7 +88,7 @@ struct AnimatedAppWizard : public NewProjectWizard if (createCppFile) { String windowCpp = project.getFileTemplate ("jucer_AnimatedComponentTemplate_cpp") - .replace ("%%include_juce%%", CodeHelpers::createIncludeStatement (project.getAppIncludeFile(), contentCompCpp), false) + .replace ("%%include_juce%%", juceHeaderInclude) .replace ("%%include_corresponding_header%%", CodeHelpers::createIncludeStatement (contentCompH, contentCompCpp), false) .replace ("%%content_component_class%%", contentCompName, false); diff --git a/extras/Projucer/Source/Wizards/jucer_ProjectWizard_AudioApp.h b/extras/Projucer/Source/Wizards/jucer_ProjectWizard_AudioApp.h index 80aa745f..45eed357 100644 --- a/extras/Projucer/Source/Wizards/jucer_ProjectWizard_AudioApp.h +++ b/extras/Projucer/Source/Wizards/jucer_ProjectWizard_AudioApp.h @@ -71,14 +71,13 @@ struct AudioAppWizard : public NewProjectWizard setExecutableNameForAllTargets (project, File::createLegalFileName (appTitle)); - String appHeaders (CodeHelpers::createIncludeStatement (project.getAppIncludeFile(), mainCppFile)); + auto juceHeaderInclude = CodeHelpers::createIncludePathIncludeStatement (Project::getJuceSourceHFilename()); + auto appHeaders = juceHeaderInclude + newLine + CodeHelpers::createIncludeStatement (contentCompH, mainCppFile); // create main window - appHeaders << newLine << CodeHelpers::createIncludeStatement (contentCompH, mainCppFile); - String windowH = project.getFileTemplate (createCppFile ? "jucer_AudioComponentTemplate_h" : "jucer_AudioComponentSimpleTemplate_h") - .replace ("%%include_juce%%", CodeHelpers::createIncludeStatement (project.getAppIncludeFile(), contentCompH), false) + .replace ("%%include_juce%%", juceHeaderInclude) .replace ("%%content_component_class%%", contentCompName, false); if (! FileHelpers::overwriteFileWithNewDataIfDifferent (contentCompH, windowH)) @@ -89,7 +88,7 @@ struct AudioAppWizard : public NewProjectWizard if (createCppFile) { String windowCpp = project.getFileTemplate ("jucer_AudioComponentTemplate_cpp") - .replace ("%%include_juce%%", CodeHelpers::createIncludeStatement (project.getAppIncludeFile(), contentCompCpp), false) + .replace ("%%include_juce%%", juceHeaderInclude) .replace ("%%include_corresponding_header%%", CodeHelpers::createIncludeStatement (contentCompH, contentCompCpp), false) .replace ("%%content_component_class%%", contentCompName, false); diff --git a/extras/Projucer/Source/Wizards/jucer_ProjectWizard_AudioPlugin.h b/extras/Projucer/Source/Wizards/jucer_ProjectWizard_AudioPlugin.h index b81d2874..767efd83 100644 --- a/extras/Projucer/Source/Wizards/jucer_ProjectWizard_AudioPlugin.h +++ b/extras/Projucer/Source/Wizards/jucer_ProjectWizard_AudioPlugin.h @@ -62,7 +62,7 @@ struct AudioPluginAppWizard : public NewProjectWizard setExecutableNameForAllTargets (project, File::createLegalFileName (appTitle)); - String appHeaders (CodeHelpers::createIncludeStatement (project.getAppIncludeFile(), filterCppFile)); + auto juceHeaderInclude = CodeHelpers::createIncludePathIncludeStatement (Project::getJuceSourceHFilename()); String filterCpp = project.getFileTemplate ("jucer_AudioPluginFilterTemplate_cpp") .replace ("%%filter_headers%%", CodeHelpers::createIncludeStatement (filterHFile, filterCppFile) @@ -71,7 +71,7 @@ struct AudioPluginAppWizard : public NewProjectWizard .replace ("%%editor_class_name%%", editorClassName, false); String filterH = project.getFileTemplate ("jucer_AudioPluginFilterTemplate_h") - .replace ("%%app_headers%%", appHeaders, false) + .replace ("%%app_headers%%", juceHeaderInclude, false) .replace ("%%filter_class_name%%", filterClassName, false); String editorCpp = project.getFileTemplate ("jucer_AudioPluginEditorTemplate_cpp") @@ -81,7 +81,7 @@ struct AudioPluginAppWizard : public NewProjectWizard .replace ("%%editor_class_name%%", editorClassName, false); String editorH = project.getFileTemplate ("jucer_AudioPluginEditorTemplate_h") - .replace ("%%editor_headers%%", appHeaders + newLine + CodeHelpers::createIncludeStatement (filterHFile, filterCppFile), false) + .replace ("%%editor_headers%%", juceHeaderInclude + newLine + CodeHelpers::createIncludeStatement (filterHFile, filterCppFile), false) .replace ("%%filter_class_name%%", filterClassName, false) .replace ("%%editor_class_name%%", editorClassName, false); diff --git a/extras/Projucer/Source/Wizards/jucer_ProjectWizard_Console.h b/extras/Projucer/Source/Wizards/jucer_ProjectWizard_Console.h index 277bd8b0..3aba175c 100644 --- a/extras/Projucer/Source/Wizards/jucer_ProjectWizard_Console.h +++ b/extras/Projucer/Source/Wizards/jucer_ProjectWizard_Console.h @@ -69,10 +69,9 @@ struct ConsoleAppWizard : public NewProjectWizard if (createMainCpp) { File mainCppFile = getSourceFilesFolder().getChildFile ("Main.cpp"); - String appHeaders (CodeHelpers::createIncludeStatement (project.getAppIncludeFile(), mainCppFile)); String mainCpp = project.getFileTemplate ("jucer_MainConsoleAppTemplate_cpp") - .replace ("%%app_headers%%", appHeaders, false); + .replace ("%%app_headers%%", CodeHelpers::createIncludePathIncludeStatement (Project::getJuceSourceHFilename()), false); if (! FileHelpers::overwriteFileWithNewDataIfDifferent (mainCppFile, mainCpp)) failedFiles.add (mainCppFile.getFullPathName()); diff --git a/extras/Projucer/Source/Wizards/jucer_ProjectWizard_GUIApp.h b/extras/Projucer/Source/Wizards/jucer_ProjectWizard_GUIApp.h index 2f39be9a..710ae576 100644 --- a/extras/Projucer/Source/Wizards/jucer_ProjectWizard_GUIApp.h +++ b/extras/Projucer/Source/Wizards/jucer_ProjectWizard_GUIApp.h @@ -75,7 +75,8 @@ struct GUIAppWizard : public NewProjectWizard setExecutableNameForAllTargets (project, File::createLegalFileName (appTitle)); - String appHeaders (CodeHelpers::createIncludeStatement (project.getAppIncludeFile(), mainCppFile)); + auto juceHeaderInclude = CodeHelpers::createIncludePathIncludeStatement (Project::getJuceSourceHFilename()); + auto appHeaders = juceHeaderInclude; if (createWindow) { @@ -83,7 +84,7 @@ struct GUIAppWizard : public NewProjectWizard String windowH = project.getFileTemplate (createCppFile ? "jucer_ContentCompTemplate_h" : "jucer_ContentCompSimpleTemplate_h") - .replace ("%%include_juce%%", CodeHelpers::createIncludeStatement (project.getAppIncludeFile(), contentCompH), false) + .replace ("%%include_juce%%", juceHeaderInclude) .replace ("%%content_component_class%%", contentCompName, false); if (! FileHelpers::overwriteFileWithNewDataIfDifferent (contentCompH, windowH)) @@ -94,7 +95,7 @@ struct GUIAppWizard : public NewProjectWizard if (createCppFile) { String windowCpp = project.getFileTemplate ("jucer_ContentCompTemplate_cpp") - .replace ("%%include_juce%%", CodeHelpers::createIncludeStatement (project.getAppIncludeFile(), contentCompCpp), false) + .replace ("%%include_juce%%", juceHeaderInclude) .replace ("%%include_corresponding_header%%", CodeHelpers::createIncludeStatement (contentCompH, contentCompCpp), false) .replace ("%%content_component_class%%", contentCompName, false); diff --git a/extras/Projucer/Source/Wizards/jucer_ProjectWizard_openGL.h b/extras/Projucer/Source/Wizards/jucer_ProjectWizard_openGL.h index 44dee4c0..29b092b2 100644 --- a/extras/Projucer/Source/Wizards/jucer_ProjectWizard_openGL.h +++ b/extras/Projucer/Source/Wizards/jucer_ProjectWizard_openGL.h @@ -71,14 +71,13 @@ struct OpenGLAppWizard : public NewProjectWizard setExecutableNameForAllTargets (project, File::createLegalFileName (appTitle)); - String appHeaders (CodeHelpers::createIncludeStatement (project.getAppIncludeFile(), mainCppFile)); + auto juceHeaderInclude = CodeHelpers::createIncludePathIncludeStatement (Project::getJuceSourceHFilename()); + auto appHeaders = juceHeaderInclude + newLine + CodeHelpers::createIncludeStatement (contentCompH, mainCppFile); // create main window - appHeaders << newLine << CodeHelpers::createIncludeStatement (contentCompH, mainCppFile); - String windowH = project.getFileTemplate (createCppFile ? "jucer_OpenGLComponentTemplate_h" : "jucer_OpenGLComponentSimpleTemplate_h") - .replace ("%%include_juce%%", CodeHelpers::createIncludeStatement (project.getAppIncludeFile(), contentCompH), false) + .replace ("%%include_juce%%", juceHeaderInclude) .replace ("%%content_component_class%%", contentCompName, false); if (! FileHelpers::overwriteFileWithNewDataIfDifferent (contentCompH, windowH)) @@ -89,7 +88,7 @@ struct OpenGLAppWizard : public NewProjectWizard if (createCppFile) { String windowCpp = project.getFileTemplate ("jucer_OpenGLComponentTemplate_cpp") - .replace ("%%include_juce%%", CodeHelpers::createIncludeStatement (project.getAppIncludeFile(), contentCompCpp), false) + .replace ("%%include_juce%%", juceHeaderInclude) .replace ("%%include_corresponding_header%%", CodeHelpers::createIncludeStatement (contentCompH, contentCompCpp), false) .replace ("%%content_component_class%%", contentCompName, false); diff --git a/extras/UnitTestRunner/Builds/MacOSX/ConsoleApp.entitlements b/extras/UnitTestRunner/Builds/MacOSX/ConsoleApp.entitlements new file mode 100644 index 00000000..6631ffa6 --- /dev/null +++ b/extras/UnitTestRunner/Builds/MacOSX/ConsoleApp.entitlements @@ -0,0 +1,6 @@ + + + + + + diff --git a/extras/UnitTestRunner/Builds/MacOSX/UnitTestRunner.entitlements b/extras/UnitTestRunner/Builds/MacOSX/UnitTestRunner.entitlements deleted file mode 100644 index 6631ffa6..00000000 --- a/extras/UnitTestRunner/Builds/MacOSX/UnitTestRunner.entitlements +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/extras/UnitTestRunner/Builds/MacOSX/UnitTestRunner.xcodeproj/project.pbxproj b/extras/UnitTestRunner/Builds/MacOSX/UnitTestRunner.xcodeproj/project.pbxproj index 02ced2bb..5ac149dc 100644 --- a/extras/UnitTestRunner/Builds/MacOSX/UnitTestRunner.xcodeproj/project.pbxproj +++ b/extras/UnitTestRunner/Builds/MacOSX/UnitTestRunner.xcodeproj/project.pbxproj @@ -398,13 +398,6 @@ path = System/Library/Frameworks/CoreMedia.framework; sourceTree = SDKROOT; }; - 911BC81C9C4E07C2E2FD68C1 = { - isa = PBXFileReference; - lastKnownFileType = text.plist.xml; - name = UnitTestRunner.entitlements; - path = UnitTestRunner.entitlements; - sourceTree = "SOURCE_ROOT"; - }; 9514F6D920549F8A44B2E332 = { isa = PBXFileReference; lastKnownFileType = file; @@ -817,6 +810,7 @@ GCC_WARN_UNUSED_VARIABLE = YES; ONLY_ACTIVE_ARCH = YES; PRODUCT_NAME = "UnitTestRunner"; + SDKROOT = macosx; WARNING_CFLAGS = "-Wreorder"; ZERO_LINK = NO; }; @@ -862,6 +856,7 @@ GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; PRODUCT_NAME = "UnitTestRunner"; + SDKROOT = macosx; WARNING_CFLAGS = "-Wreorder"; ZERO_LINK = NO; }; diff --git a/extras/UnitTestRunner/Builds/VisualStudio2017/UnitTestRunner_ConsoleApp.vcxproj b/extras/UnitTestRunner/Builds/VisualStudio2017/UnitTestRunner_ConsoleApp.vcxproj index b6d6721d..a6ada508 100644 --- a/extras/UnitTestRunner/Builds/VisualStudio2017/UnitTestRunner_ConsoleApp.vcxproj +++ b/extras/UnitTestRunner/Builds/VisualStudio2017/UnitTestRunner_ConsoleApp.vcxproj @@ -821,9 +821,6 @@ true - - true - true @@ -974,6 +971,9 @@ true + + true + true @@ -2443,7 +2443,6 @@ - diff --git a/extras/UnitTestRunner/Builds/VisualStudio2017/UnitTestRunner_ConsoleApp.vcxproj.filters b/extras/UnitTestRunner/Builds/VisualStudio2017/UnitTestRunner_ConsoleApp.vcxproj.filters index 40c5b96d..e7fc4f99 100644 --- a/extras/UnitTestRunner/Builds/VisualStudio2017/UnitTestRunner_ConsoleApp.vcxproj.filters +++ b/extras/UnitTestRunner/Builds/VisualStudio2017/UnitTestRunner_ConsoleApp.vcxproj.filters @@ -1204,9 +1204,6 @@ JUCE Modules\juce_core\misc - - JUCE Modules\juce_core\misc - JUCE Modules\juce_core\misc @@ -1372,6 +1369,9 @@ JUCE Modules\juce_core\threads + + JUCE Modules\juce_core\threads + JUCE Modules\juce_core\time @@ -3642,9 +3642,6 @@ JUCE Modules\juce_core\misc - - JUCE Modules\juce_core\misc - JUCE Modules\juce_core\misc diff --git a/extras/UnitTestRunner/Builds/VisualStudio2019/UnitTestRunner_ConsoleApp.vcxproj b/extras/UnitTestRunner/Builds/VisualStudio2019/UnitTestRunner_ConsoleApp.vcxproj index 8fda3982..9da5d1f4 100644 --- a/extras/UnitTestRunner/Builds/VisualStudio2019/UnitTestRunner_ConsoleApp.vcxproj +++ b/extras/UnitTestRunner/Builds/VisualStudio2019/UnitTestRunner_ConsoleApp.vcxproj @@ -821,9 +821,6 @@ true - - true - true @@ -974,6 +971,9 @@ true + + true + true @@ -2443,7 +2443,6 @@ - diff --git a/extras/UnitTestRunner/Builds/VisualStudio2019/UnitTestRunner_ConsoleApp.vcxproj.filters b/extras/UnitTestRunner/Builds/VisualStudio2019/UnitTestRunner_ConsoleApp.vcxproj.filters index 473a89cd..968333e7 100644 --- a/extras/UnitTestRunner/Builds/VisualStudio2019/UnitTestRunner_ConsoleApp.vcxproj.filters +++ b/extras/UnitTestRunner/Builds/VisualStudio2019/UnitTestRunner_ConsoleApp.vcxproj.filters @@ -1204,9 +1204,6 @@ JUCE Modules\juce_core\misc - - JUCE Modules\juce_core\misc - JUCE Modules\juce_core\misc @@ -1372,6 +1369,9 @@ JUCE Modules\juce_core\threads + + JUCE Modules\juce_core\threads + JUCE Modules\juce_core\time @@ -3642,9 +3642,6 @@ JUCE Modules\juce_core\misc - - JUCE Modules\juce_core\misc - JUCE Modules\juce_core\misc diff --git a/extras/UnitTestRunner/JuceLibraryCode/AppConfig.h b/extras/UnitTestRunner/JuceLibraryCode/AppConfig.h index e270488f..87396c71 100644 --- a/extras/UnitTestRunner/JuceLibraryCode/AppConfig.h +++ b/extras/UnitTestRunner/JuceLibraryCode/AppConfig.h @@ -47,7 +47,7 @@ #define JUCE_USE_DARK_SPLASH_SCREEN 1 -#define JUCE_PROJUCER_VERSION 0x50405 +#define JUCE_PROJUCER_VERSION 0x50406 //============================================================================== #define JUCE_MODULE_AVAILABLE_juce_analytics 1 @@ -241,8 +241,8 @@ //============================================================================== // juce_events flags: -#ifndef JUCE_EXECUTE_APP_SUSPEND_ON_IOS_BACKGROUND_TASK - //#define JUCE_EXECUTE_APP_SUSPEND_ON_IOS_BACKGROUND_TASK 0 +#ifndef JUCE_EXECUTE_APP_SUSPEND_ON_BACKGROUND_TASK + //#define JUCE_EXECUTE_APP_SUSPEND_ON_BACKGROUND_TASK 0 #endif //============================================================================== diff --git a/extras/UnitTestRunner/Source/Main.cpp b/extras/UnitTestRunner/Source/Main.cpp index 47ebd682..3c9a56ad 100644 --- a/extras/UnitTestRunner/Source/Main.cpp +++ b/extras/UnitTestRunner/Source/Main.cpp @@ -24,7 +24,7 @@ ============================================================================== */ -#include "../JuceLibraryCode/JuceHeader.h" +#include //============================================================================== class ConsoleLogger : public Logger diff --git a/extras/UnitTestRunner/UnitTestRunner.jucer b/extras/UnitTestRunner/UnitTestRunner.jucer index 6cbcabaa..d0f8dcb2 100644 --- a/extras/UnitTestRunner/UnitTestRunner.jucer +++ b/extras/UnitTestRunner/UnitTestRunner.jucer @@ -1,7 +1,7 @@ diff --git a/extras/WindowsDLL/Builds/VisualStudio2019/WindowsDLL_StaticLibrary.vcxproj b/extras/WindowsDLL/Builds/VisualStudio2019/WindowsDLL_StaticLibrary.vcxproj index 7ffe29c8..44747945 100644 --- a/extras/WindowsDLL/Builds/VisualStudio2019/WindowsDLL_StaticLibrary.vcxproj +++ b/extras/WindowsDLL/Builds/VisualStudio2019/WindowsDLL_StaticLibrary.vcxproj @@ -750,9 +750,6 @@ true - - true - true @@ -903,6 +900,9 @@ true + + true + true @@ -2226,7 +2226,6 @@ - diff --git a/extras/WindowsDLL/Builds/VisualStudio2019/WindowsDLL_StaticLibrary.vcxproj.filters b/extras/WindowsDLL/Builds/VisualStudio2019/WindowsDLL_StaticLibrary.vcxproj.filters index 651289cb..b521de4d 100644 --- a/extras/WindowsDLL/Builds/VisualStudio2019/WindowsDLL_StaticLibrary.vcxproj.filters +++ b/extras/WindowsDLL/Builds/VisualStudio2019/WindowsDLL_StaticLibrary.vcxproj.filters @@ -1060,9 +1060,6 @@ JUCE Modules\juce_core\misc - - JUCE Modules\juce_core\misc - JUCE Modules\juce_core\misc @@ -1228,6 +1225,9 @@ JUCE Modules\juce_core\threads + + JUCE Modules\juce_core\threads + JUCE Modules\juce_core\time @@ -3276,9 +3276,6 @@ JUCE Modules\juce_core\misc - - JUCE Modules\juce_core\misc - JUCE Modules\juce_core\misc diff --git a/extras/WindowsDLL/JuceLibraryCode/AppConfig.h b/extras/WindowsDLL/JuceLibraryCode/AppConfig.h index 146de870..5a607cdb 100644 --- a/extras/WindowsDLL/JuceLibraryCode/AppConfig.h +++ b/extras/WindowsDLL/JuceLibraryCode/AppConfig.h @@ -47,7 +47,7 @@ #define JUCE_USE_DARK_SPLASH_SCREEN 1 -#define JUCE_PROJUCER_VERSION 0x50405 +#define JUCE_PROJUCER_VERSION 0x50406 //============================================================================== #define JUCE_MODULE_AVAILABLE_juce_audio_basics 1 @@ -213,8 +213,8 @@ //============================================================================== // juce_events flags: -#ifndef JUCE_EXECUTE_APP_SUSPEND_ON_IOS_BACKGROUND_TASK - //#define JUCE_EXECUTE_APP_SUSPEND_ON_IOS_BACKGROUND_TASK 0 +#ifndef JUCE_EXECUTE_APP_SUSPEND_ON_BACKGROUND_TASK + //#define JUCE_EXECUTE_APP_SUSPEND_ON_BACKGROUND_TASK 0 #endif //============================================================================== diff --git a/extras/WindowsDLL/WindowsDLL.jucer b/extras/WindowsDLL/WindowsDLL.jucer index d713ca99..6eda8d9f 100644 --- a/extras/WindowsDLL/WindowsDLL.jucer +++ b/extras/WindowsDLL/WindowsDLL.jucer @@ -1,7 +1,7 @@ diff --git a/modules/juce_analytics/analytics/juce_ButtonTracker.h b/modules/juce_analytics/analytics/juce_ButtonTracker.h index 8b005bba..a385c6ad 100644 --- a/modules/juce_analytics/analytics/juce_ButtonTracker.h +++ b/modules/juce_analytics/analytics/juce_ButtonTracker.h @@ -42,7 +42,7 @@ public: //============================================================================== /** Creating one of these automatically sends analytics events to the Analytics - singeton when the corresponding button is clicked. + singleton when the corresponding button is clicked. The name and parameters of the analytics event will be populated from the variables supplied here. If clicking changes the button's state then the diff --git a/modules/juce_analytics/juce_analytics.h b/modules/juce_analytics/juce_analytics.h index 0bf9255e..aef59e71 100644 --- a/modules/juce_analytics/juce_analytics.h +++ b/modules/juce_analytics/juce_analytics.h @@ -24,6 +24,7 @@ ============================================================================== */ + /******************************************************************************* The block below describes the properties of this module, and is read by the Projucer to automatically generate project code that uses it. @@ -33,15 +34,15 @@ BEGIN_JUCE_MODULE_DECLARATION - ID: juce_analytics - vendor: juce - version: 5.4.5 - name: JUCE analytics classes - description: Classes to collect analytics and send to destinations - website: http://www.juce.com/juce - license: GPL/Commercial + ID: juce_analytics + vendor: juce + version: 5.4.6 + name: JUCE analytics classes + description: Classes to collect analytics and send to destinations + website: http://www.juce.com/juce + license: GPL/Commercial - dependencies: juce_gui_basics + dependencies: juce_gui_basics END_JUCE_MODULE_DECLARATION diff --git a/modules/juce_audio_basics/buffers/juce_AudioProcessLoadMeasurer.h b/modules/juce_audio_basics/buffers/juce_AudioProcessLoadMeasurer.h index 53a3377c..8cf59706 100644 --- a/modules/juce_audio_basics/buffers/juce_AudioProcessLoadMeasurer.h +++ b/modules/juce_audio_basics/buffers/juce_AudioProcessLoadMeasurer.h @@ -31,6 +31,8 @@ namespace juce /** Maintains an ongoing measurement of the proportion of time which is being spent inside an audio callback. + + @tags{Audio} */ class JUCE_API AudioProcessLoadMeasurer { @@ -68,6 +70,8 @@ public: myCallback->doTheCallback(); } @endcode + + @tags{Audio} */ struct JUCE_API ScopedTimer { diff --git a/modules/juce_audio_basics/buffers/juce_AudioSampleBuffer.h b/modules/juce_audio_basics/buffers/juce_AudioSampleBuffer.h index 5e68694a..f4ab1df0 100644 --- a/modules/juce_audio_basics/buffers/juce_AudioSampleBuffer.h +++ b/modules/juce_audio_basics/buffers/juce_AudioSampleBuffer.h @@ -116,7 +116,7 @@ public: /** Copies another buffer. This buffer will make its own copy of the other's data, unless the buffer was created - using an external data buffer, in which case boths buffers will just point to the same + using an external data buffer, in which case both buffers will just point to the same shared block of data. */ AudioBuffer (const AudioBuffer& other) @@ -1075,8 +1075,17 @@ private: void allocateData() { + static_assert (std::alignment_of::value <= std::alignment_of::value, + "AudioBuffer cannot hold types with alignment requirements larger than that guaranteed by malloc"); jassert (size >= 0); + auto channelListSize = (size_t) (numChannels + 1) * sizeof (Type*); + auto requiredSampleAlignment = std::alignment_of::value; + size_t alignmentOverflow = channelListSize % requiredSampleAlignment; + + if (alignmentOverflow != 0) + channelListSize += requiredSampleAlignment - alignmentOverflow; + allocatedBytes = (size_t) numChannels * (size_t) size * sizeof (Type) + channelListSize + 32; allocatedData.malloc (allocatedBytes); channels = reinterpret_cast (allocatedData.get()); diff --git a/modules/juce_audio_basics/juce_audio_basics.h b/modules/juce_audio_basics/juce_audio_basics.h index 83a10831..53556a41 100644 --- a/modules/juce_audio_basics/juce_audio_basics.h +++ b/modules/juce_audio_basics/juce_audio_basics.h @@ -20,6 +20,7 @@ ============================================================================== */ + /******************************************************************************* The block below describes the properties of this module, and is read by the Projucer to automatically generate project code that uses it. @@ -29,17 +30,17 @@ BEGIN_JUCE_MODULE_DECLARATION - ID: juce_audio_basics - vendor: juce - version: 5.4.5 - name: JUCE audio and MIDI data classes - description: Classes for audio buffer manipulation, midi message handling, synthesis, etc. - website: http://www.juce.com/juce - license: ISC - - dependencies: juce_core - OSXFrameworks: Accelerate - iOSFrameworks: Accelerate + ID: juce_audio_basics + vendor: juce + version: 5.4.6 + name: JUCE audio and MIDI data classes + description: Classes for audio buffer manipulation, midi message handling, synthesis, etc. + website: http://www.juce.com/juce + license: ISC + + dependencies: juce_core + OSXFrameworks: Accelerate + iOSFrameworks: Accelerate END_JUCE_MODULE_DECLARATION diff --git a/modules/juce_audio_basics/midi/juce_MidiKeyboardState.h b/modules/juce_audio_basics/midi/juce_MidiKeyboardState.h index 5b20bc57..47aaf692 100644 --- a/modules/juce_audio_basics/midi/juce_MidiKeyboardState.h +++ b/modules/juce_audio_basics/midi/juce_MidiKeyboardState.h @@ -73,7 +73,7 @@ public: Represents a piano keyboard, keeping track of which keys are currently pressed. This object can parse a stream of midi events, using them to update its idea - of which keys are pressed for each individiual midi channel. + of which keys are pressed for each individual midi channel. When keys go up or down, it can broadcast these events to listener objects. @@ -135,7 +135,7 @@ public: It will also trigger a synchronous callback to the listeners to tell them that the key has gone up. - But if the note isn't acutally down for the given channel, this method will in fact do nothing. + But if the note isn't actually down for the given channel, this method will in fact do nothing. */ void noteOff (int midiChannel, int midiNoteNumber, float velocity); diff --git a/modules/juce_audio_basics/midi/juce_MidiMessageSequence.cpp b/modules/juce_audio_basics/midi/juce_MidiMessageSequence.cpp index f58fd788..d74aa583 100644 --- a/modules/juce_audio_basics/midi/juce_MidiMessageSequence.cpp +++ b/modules/juce_audio_basics/midi/juce_MidiMessageSequence.cpp @@ -378,7 +378,7 @@ struct MidiMessageSequenceTest : public UnitTest expectEquals (s.getIndexOfMatchingKeyUp (0), 2); expectEquals (s.getIndexOfMatchingKeyUp (1), 3); - beginTest ("Time & indeces"); + beginTest ("Time & indices"); expectEquals (s.getNextIndexAtTime (0.5), 1); expectEquals (s.getNextIndexAtTime (2.5), 2); expectEquals (s.getNextIndexAtTime (9.0), 4); diff --git a/modules/juce_audio_basics/midi/juce_MidiRPN.h b/modules/juce_audio_basics/midi/juce_MidiRPN.h index 94ffc731..869afac7 100644 --- a/modules/juce_audio_basics/midi/juce_MidiRPN.h +++ b/modules/juce_audio_basics/midi/juce_MidiRPN.h @@ -142,7 +142,7 @@ public: @param use14BitValue If true (default), the value will have 14-bit precision (two MIDI bytes). If false, instead the value will have - 7-bit presision (a single MIDI byte). + 7-bit precision (a single MIDI byte). */ static MidiBuffer generate (int channel, int parameterNumber, diff --git a/modules/juce_audio_basics/mpe/juce_MPEInstrument.h b/modules/juce_audio_basics/mpe/juce_MPEInstrument.h index 1f0b132d..91a0b2b3 100644 --- a/modules/juce_audio_basics/mpe/juce_MPEInstrument.h +++ b/modules/juce_audio_basics/mpe/juce_MPEInstrument.h @@ -27,7 +27,7 @@ namespace juce /** This class represents an instrument handling MPE. - It has an MPE zone layout and maintans a state of currently + It has an MPE zone layout and maintains a state of currently active (playing) notes and the values of their dimensions of expression. You can trigger and modulate notes: diff --git a/modules/juce_audio_basics/mpe/juce_MPEMessages.h b/modules/juce_audio_basics/mpe/juce_MPEMessages.h index a6e31e85..1275dacd 100644 --- a/modules/juce_audio_basics/mpe/juce_MPEMessages.h +++ b/modules/juce_audio_basics/mpe/juce_MPEMessages.h @@ -99,7 +99,7 @@ public: /** Returns the sequence of MIDI messages that, if sent to an Expressive MIDI device, will reset the whole MPE zone layout of the - device to the laoyut passed in. This will first clear the current lower and upper + device to the layout passed in. This will first clear the current lower and upper zones, then then set the zones contained in the passed-in zone layout, and set their per-note and master pitchbend ranges to their current values. */ diff --git a/modules/juce_audio_basics/mpe/juce_MPESynthesiser.h b/modules/juce_audio_basics/mpe/juce_MPESynthesiser.h index 587ce4df..8a999d66 100644 --- a/modules/juce_audio_basics/mpe/juce_MPESynthesiser.h +++ b/modules/juce_audio_basics/mpe/juce_MPESynthesiser.h @@ -247,7 +247,7 @@ protected: int numSamples) override; /** This will simply call renderNextBlock for each currently active - voice and fill the buffer with the sum. (souble-precision version) + voice and fill the buffer with the sum. (double-precision version) Override this method if you need to do more work to render your audio. */ void renderNextSubBlock (AudioBuffer& outputAudio, diff --git a/modules/juce_audio_basics/mpe/juce_MPEUtils.cpp b/modules/juce_audio_basics/mpe/juce_MPEUtils.cpp index b8d973c2..8ebc185b 100644 --- a/modules/juce_audio_basics/mpe/juce_MPEUtils.cpp +++ b/modules/juce_audio_basics/mpe/juce_MPEUtils.cpp @@ -49,7 +49,7 @@ MPEChannelAssigner::MPEChannelAssigner (Range channelRange) int MPEChannelAssigner::findMidiChannelForNewNote (int noteNumber) noexcept { - if (numChannels == 1) + if (numChannels <= 1) return firstChannel; for (auto ch = firstChannel; (isLegacy || zone->isLowerZone() ? ch <= lastChannel : ch >= lastChannel); ch += channelIncrement) diff --git a/modules/juce_audio_basics/sources/juce_AudioSource.h b/modules/juce_audio_basics/sources/juce_AudioSource.h index 3b48ee06..401c4f77 100644 --- a/modules/juce_audio_basics/sources/juce_AudioSource.h +++ b/modules/juce_audio_basics/sources/juce_AudioSource.h @@ -122,7 +122,7 @@ public: An AudioSource has two states: prepared and unprepared. - The prepareToPlay() method is guaranteed to be called at least once on an 'unpreprared' + The prepareToPlay() method is guaranteed to be called at least once on an 'unprepared' source to put it into a 'prepared' state before any calls will be made to getNextAudioBlock(). This callback allows the source to initialise any resources it might need when playing. diff --git a/modules/juce_audio_basics/utilities/juce_ADSR.h b/modules/juce_audio_basics/utilities/juce_ADSR.h index 6de3e8da..8f50ceef 100644 --- a/modules/juce_audio_basics/utilities/juce_ADSR.h +++ b/modules/juce_audio_basics/utilities/juce_ADSR.h @@ -30,6 +30,8 @@ namespace juce To use it, call setSampleRate() with the current sample rate and give it some parameters with setParameters() then call getNextSample() to get the envelope value to be applied to each audio sample or applyEnvelopeToBuffer() to apply the envelope to a whole buffer. + + @tags{Audio} */ class ADSR { @@ -42,7 +44,11 @@ public: } //============================================================================== - /** Holds the parameters being used by an ADSR object. */ + /** + Holds the parameters being used by an ADSR object. + + @tags{Audio} + */ struct Parameters { /** Attack time in seconds. */ @@ -102,12 +108,6 @@ public: { envelopeVal = 0.0f; currentState = State::idle; - - if (resetReleaseRate) - { - releaseRate = static_cast (sustainLevel / (currentParameters.release * sr)); - resetReleaseRate = false; - } } /** Starts the attack phase of the envelope. */ @@ -133,14 +133,9 @@ public: { if (currentState != State::idle) { - if (releaseRate > 0.0f) + if (currentParameters.release > 0.0f) { - if (currentState != State::sustain) - { - releaseRate = static_cast (envelopeVal / (currentParameters.release * sr)); - resetReleaseRate = true; - } - + releaseRate = static_cast (envelopeVal / (currentParameters.release * sr)); currentState = State::release; } else @@ -231,7 +226,6 @@ private: attackRate = (parameters.attack > 0.0f ? static_cast (1.0f / (parameters.attack * sr)) : -1.0f); decayRate = (parameters.decay > 0.0f ? static_cast ((1.0f - sustainLevel) / (parameters.decay * sr)) : -1.0f); - releaseRate = (parameters.release > 0.0f ? static_cast (sustainLevel / (parameters.release * sr)) : -1.0f); } void checkCurrentState() @@ -249,7 +243,6 @@ private: double sr = 0.0; float envelopeVal = 0.0f, sustainLevel = 0.0f, attackRate = 0.0f, decayRate = 0.0f, releaseRate = 0.0f; - bool resetReleaseRate = false; }; } // namespace juce diff --git a/modules/juce_audio_basics/utilities/juce_SmoothedValue.h b/modules/juce_audio_basics/utilities/juce_SmoothedValue.h index ac6073e3..a472fb00 100644 --- a/modules/juce_audio_basics/utilities/juce_SmoothedValue.h +++ b/modules/juce_audio_basics/utilities/juce_SmoothedValue.h @@ -179,10 +179,18 @@ protected: */ namespace ValueSmoothingTypes { - /** Used to indicate a linear smoothing between values. */ + /** + Used to indicate a linear smoothing between values. + + @tags{Audio} + */ struct Linear {}; - /** Used to indicate a smoothing between multiplicative values. */ + /** + Used to indicate a smoothing between multiplicative values. + + @tags{Audio} + */ struct Multiplicative {}; } diff --git a/modules/juce_audio_devices/audio_io/juce_AudioDeviceManager.cpp b/modules/juce_audio_devices/audio_io/juce_AudioDeviceManager.cpp index a26a3bf4..7c8625c5 100644 --- a/modules/juce_audio_devices/audio_io/juce_AudioDeviceManager.cpp +++ b/modules/juce_audio_devices/audio_io/juce_AudioDeviceManager.cpp @@ -105,7 +105,7 @@ void AudioDeviceManager::createDeviceTypesIfNeeded() createAudioDeviceTypes (types); for (auto* t : types) - addAudioDeviceType (t); + addAudioDeviceType (std::unique_ptr (t)); types.clear (false); @@ -172,23 +172,40 @@ void AudioDeviceManager::createAudioDeviceTypes (OwnedArray& addIfNotNull (list, AudioIODeviceType::createAudioIODeviceType_ASIO()); addIfNotNull (list, AudioIODeviceType::createAudioIODeviceType_CoreAudio()); addIfNotNull (list, AudioIODeviceType::createAudioIODeviceType_iOSAudio()); + addIfNotNull (list, AudioIODeviceType::createAudioIODeviceType_Bela()); addIfNotNull (list, AudioIODeviceType::createAudioIODeviceType_ALSA()); addIfNotNull (list, AudioIODeviceType::createAudioIODeviceType_JACK()); - addIfNotNull (list, AudioIODeviceType::createAudioIODeviceType_Bela()); addIfNotNull (list, AudioIODeviceType::createAudioIODeviceType_Oboe()); addIfNotNull (list, AudioIODeviceType::createAudioIODeviceType_OpenSLES()); addIfNotNull (list, AudioIODeviceType::createAudioIODeviceType_Android()); } -void AudioDeviceManager::addAudioDeviceType (AudioIODeviceType* newDeviceType) +void AudioDeviceManager::addAudioDeviceType (std::unique_ptr newDeviceType) { if (newDeviceType != nullptr) { jassert (lastDeviceTypeConfigs.size() == availableDeviceTypes.size()); - availableDeviceTypes.add (newDeviceType); + + availableDeviceTypes.add (newDeviceType.release()); lastDeviceTypeConfigs.add (new AudioDeviceSetup()); - newDeviceType->addListener (callbackHandler.get()); + availableDeviceTypes.getLast()->addListener (callbackHandler.get()); + } +} + +void AudioDeviceManager::removeAudioDeviceType (AudioIODeviceType* deviceTypeToRemove) +{ + if (deviceTypeToRemove != nullptr) + { + jassert (lastDeviceTypeConfigs.size() == availableDeviceTypes.size()); + + auto index = availableDeviceTypes.indexOf (deviceTypeToRemove); + + if (auto removed = std::unique_ptr (availableDeviceTypes.removeAndReturn (index))) + { + removed->removeListener (callbackHandler.get()); + lastDeviceTypeConfigs.remove (index, true); + } } } diff --git a/modules/juce_audio_devices/audio_io/juce_AudioDeviceManager.h b/modules/juce_audio_devices/audio_io/juce_AudioDeviceManager.h index 83b49c1e..b855d51e 100644 --- a/modules/juce_audio_devices/audio_io/juce_AudioDeviceManager.h +++ b/modules/juce_audio_devices/audio_io/juce_AudioDeviceManager.h @@ -391,10 +391,11 @@ public: */ virtual void createAudioDeviceTypes (OwnedArray& types); - /** Adds a new device type to the list of types. - The manager will take ownership of the object that is passed-in. - */ - void addAudioDeviceType (AudioIODeviceType* newDeviceType); + /** Adds a new device type to the list of types. */ + void addAudioDeviceType (std::unique_ptr newDeviceType); + + /** Removes a previously added device type from the manager. */ + void removeAudioDeviceType (AudioIODeviceType* deviceTypeToRemove); //============================================================================== /** Plays a beep through the current audio device. diff --git a/modules/juce_audio_devices/juce_audio_devices.h b/modules/juce_audio_devices/juce_audio_devices.h index 20a2c5f6..c39ab0f5 100644 --- a/modules/juce_audio_devices/juce_audio_devices.h +++ b/modules/juce_audio_devices/juce_audio_devices.h @@ -20,6 +20,7 @@ ============================================================================== */ + /******************************************************************************* The block below describes the properties of this module, and is read by the Projucer to automatically generate project code that uses it. @@ -29,19 +30,19 @@ BEGIN_JUCE_MODULE_DECLARATION - ID: juce_audio_devices - vendor: juce - version: 5.4.5 - name: JUCE audio and MIDI I/O device classes - description: Classes to play and record from audio and MIDI I/O devices - website: http://www.juce.com/juce - license: ISC + ID: juce_audio_devices + vendor: juce + version: 5.4.6 + name: JUCE audio and MIDI I/O device classes + description: Classes to play and record from audio and MIDI I/O devices + website: http://www.juce.com/juce + license: ISC - dependencies: juce_audio_basics, juce_events - OSXFrameworks: CoreAudio CoreMIDI AudioToolbox - iOSFrameworks: CoreAudio CoreMIDI AudioToolbox AVFoundation - linuxPackages: alsa - mingwLibs: winmm + dependencies: juce_audio_basics, juce_events + OSXFrameworks: CoreAudio CoreMIDI AudioToolbox + iOSFrameworks: CoreAudio CoreMIDI AudioToolbox AVFoundation + linuxPackages: alsa + mingwLibs: winmm END_JUCE_MODULE_DECLARATION @@ -63,7 +64,7 @@ Enables the use of the Windows Runtime API for MIDI, allowing connections to Bluetooth Low Energy devices on Windows 10 version 1809 (October 2018 Update) and later. If you enable this flag then older, unsupported, - versions of Windows will automatically fall back to using the regualar + versions of Windows will automatically fall back to using the regular Win32 MIDI API. You will need version 10.0.14393.0 of the Windows Standalone SDK to compile diff --git a/modules/juce_audio_devices/midi_io/juce_MidiDevices.h b/modules/juce_audio_devices/midi_io/juce_MidiDevices.h index eb9d7eaf..054a376a 100644 --- a/modules/juce_audio_devices/midi_io/juce_MidiDevices.h +++ b/modules/juce_audio_devices/midi_io/juce_MidiDevices.h @@ -30,6 +30,8 @@ namespace juce getDefaultDevice() methods of MidiInput and MidiOutput or by calling getDeviceInfo() on an instance of these classes. Devices can be opened by passing the identifier to the openDevice() method. + + @tags{Audio} */ struct MidiDeviceInfo { diff --git a/modules/juce_audio_devices/midi_io/juce_MidiMessageCollector.cpp b/modules/juce_audio_devices/midi_io/juce_MidiMessageCollector.cpp index 50ca2056..97f73303 100644 --- a/modules/juce_audio_devices/midi_io/juce_MidiMessageCollector.cpp +++ b/modules/juce_audio_devices/midi_io/juce_MidiMessageCollector.cpp @@ -34,9 +34,10 @@ MidiMessageCollector::~MidiMessageCollector() //============================================================================== void MidiMessageCollector::reset (const double newSampleRate) { + const ScopedLock sl (midiCallbackLock); + jassert (newSampleRate > 0); - const ScopedLock sl (midiCallbackLock); #if JUCE_DEBUG hasCalledReset = true; #endif @@ -47,6 +48,8 @@ void MidiMessageCollector::reset (const double newSampleRate) void MidiMessageCollector::addMessageToQueue (const MidiMessage& message) { + const ScopedLock sl (midiCallbackLock); + #if JUCE_DEBUG jassert (hasCalledReset); // you need to call reset() to set the correct sample rate before using this object #endif @@ -55,8 +58,6 @@ void MidiMessageCollector::addMessageToQueue (const MidiMessage& message) // for details of what the number should be. jassert (message.getTimeStamp() != 0); - const ScopedLock sl (midiCallbackLock); - auto sampleNumber = (int) ((message.getTimeStamp() - 0.001 * lastCallbackTime) * sampleRate); incomingMessages.addEvent (message, sampleNumber); @@ -70,6 +71,8 @@ void MidiMessageCollector::addMessageToQueue (const MidiMessage& message) void MidiMessageCollector::removeNextBlockOfMessages (MidiBuffer& destBuffer, const int numSamples) { + const ScopedLock sl (midiCallbackLock); + #if JUCE_DEBUG jassert (hasCalledReset); // you need to call reset() to set the correct sample rate before using this object #endif @@ -79,7 +82,6 @@ void MidiMessageCollector::removeNextBlockOfMessages (MidiBuffer& destBuffer, auto timeNow = Time::getMillisecondCounterHiRes(); auto msElapsed = timeNow - lastCallbackTime; - const ScopedLock sl (midiCallbackLock); lastCallbackTime = timeNow; if (! incomingMessages.isEmpty()) diff --git a/modules/juce_audio_devices/native/juce_android_OpenSL.cpp b/modules/juce_audio_devices/native/juce_android_OpenSL.cpp index 7e67c1d0..4a19f771 100644 --- a/modules/juce_audio_devices/native/juce_android_OpenSL.cpp +++ b/modules/juce_audio_devices/native/juce_android_OpenSL.cpp @@ -757,7 +757,7 @@ public: // only the player or the recorder should enter this section at any time if (guard.compareAndSetBool (1, 0)) { - // are there enough buffers avaialable to process some audio + // are there enough buffers available to process some audio if ((inputChannels == 0 || recorder->isBufferAvailable()) && (outputChannels == 0 || player->isBufferAvailable())) { T* recorderBuffer = (inputChannels > 0 ? recorder->getNextBuffer() : nullptr); @@ -854,7 +854,7 @@ public: 22050.0, 24000.0, 32000.0, 44100.0, 48000.0 }; Array retval (rates, numElementsInArray (rates)); - // make sure the native sample rate is pafrt of the list + // make sure the native sample rate is part of the list double native = getNativeSampleRate(); if (native != 0.0 && ! retval.contains (native)) diff --git a/modules/juce_audio_devices/native/juce_linux_ALSA.cpp b/modules/juce_audio_devices/native/juce_linux_ALSA.cpp index 9fff0b1e..f126c1dc 100644 --- a/modules/juce_audio_devices/native/juce_linux_ALSA.cpp +++ b/modules/juce_audio_devices/native/juce_linux_ALSA.cpp @@ -1249,7 +1249,7 @@ private: snd_device_name_free_hint (hints); } - // sometimes the "default" device is not listed, but it is nice to see it explicitely in the list + // sometimes the "default" device is not listed, but it is nice to see it explicitly in the list if (! outputIds.contains ("default")) testDevice ("default", "Default ALSA Output", "Default ALSA Input"); diff --git a/modules/juce_audio_devices/native/juce_linux_Bela.cpp b/modules/juce_audio_devices/native/juce_linux_Bela.cpp old mode 100755 new mode 100644 index b13eceb5..133e39bc --- a/modules/juce_audio_devices/native/juce_linux_Bela.cpp +++ b/modules/juce_audio_devices/native/juce_linux_Bela.cpp @@ -373,7 +373,7 @@ public: BigInteger getActiveInputChannels() const override { BigInteger b; b.setRange (0, actualNumberOfInputs, true); return b; } int getOutputLatencyInSamples() override { /* TODO */ return 0; } int getInputLatencyInSamples() override { /* TODO */ return 0; } - int getXRunCount() const noexcept { return underruns; } + int getXRunCount() const noexcept override { return underruns; } //============================================================================== static const char* const belaTypeName; diff --git a/modules/juce_audio_devices/native/juce_linux_JackAudio.cpp b/modules/juce_audio_devices/native/juce_linux_JackAudio.cpp index 35302a31..b916d7aa 100644 --- a/modules/juce_audio_devices/native/juce_linux_JackAudio.cpp +++ b/modules/juce_audio_devices/native/juce_linux_JackAudio.cpp @@ -105,7 +105,11 @@ namespace //============================================================================== #ifndef JUCE_JACK_CLIENT_NAME - #define JUCE_JACK_CLIENT_NAME "JUCEJack" + #ifdef JucePlugin_Name + #define JUCE_JACK_CLIENT_NAME JucePlugin_Name + #else + #define JUCE_JACK_CLIENT_NAME "JUCEJack" + #endif #endif struct JackPortIterator diff --git a/modules/juce_audio_devices/native/juce_mac_CoreAudio.cpp b/modules/juce_audio_devices/native/juce_mac_CoreAudio.cpp index 8f1004e0..86b06404 100644 --- a/modules/juce_audio_devices/native/juce_mac_CoreAudio.cpp +++ b/modules/juce_audio_devices/native/juce_mac_CoreAudio.cpp @@ -31,7 +31,7 @@ namespace juce #ifdef __clang__ #pragma clang diagnostic push - #pragma clang diagnostic ignored "-Wnonnull" // aovid some spurious 10.11 SDK warnings + #pragma clang diagnostic ignored "-Wnonnull" // avoid some spurious 10.11 SDK warnings #endif //============================================================================== diff --git a/modules/juce_audio_devices/native/juce_mac_CoreMidi.cpp b/modules/juce_audio_devices/native/juce_mac_CoreMidi.cpp index 6e9aa954..8b1e352d 100644 --- a/modules/juce_audio_devices/native/juce_mac_CoreMidi.cpp +++ b/modules/juce_audio_devices/native/juce_mac_CoreMidi.cpp @@ -499,7 +499,7 @@ std::unique_ptr MidiInput::createNewDevice (const String& deviceName, if (CHECK_ERROR (MIDIObjectSetIntegerProperty (endpoint, kMIDIPropertyUniqueID, (SInt32) deviceIdentifier))) { - mpc->portAndEndpoint = std::make_unique (0, endpoint); + mpc->portAndEndpoint = std::make_unique ((UInt32) 0, endpoint); std::unique_ptr midiInput (new MidiInput (deviceName, String (deviceIdentifier))); @@ -630,7 +630,7 @@ std::unique_ptr MidiOutput::createNewDevice (const String& deviceNam if (CHECK_ERROR (err)) { - auto deviceIdentifier = createUniqueIDForMidiPort (deviceName, true); + auto deviceIdentifier = createUniqueIDForMidiPort (deviceName, false); if (CHECK_ERROR (MIDIObjectSetIntegerProperty (endpoint, kMIDIPropertyUniqueID, (SInt32) deviceIdentifier))) { diff --git a/modules/juce_audio_devices/native/juce_win32_ASIO.cpp b/modules/juce_audio_devices/native/juce_win32_ASIO.cpp index 810c4b0a..34f438f2 100644 --- a/modules/juce_audio_devices/native/juce_win32_ASIO.cpp +++ b/modules/juce_audio_devices/native/juce_win32_ASIO.cpp @@ -43,7 +43,9 @@ namespace ASIODebugging { message = "ASIO: " + message; DBG (message); - Logger::writeToLog (message); + + if (Logger::getCurrentLogger() != nullptr) + Logger::writeToLog (message); } static void logError (const String& context, long error) @@ -336,7 +338,9 @@ public: close(); JUCE_ASIO_LOG ("closed"); - removeCurrentDriver(); + + if (! removeCurrentDriver()) + JUCE_ASIO_LOG ("** Driver crashed while being closed"); } void updateSampleRates() @@ -451,7 +455,9 @@ public: if (needToReset) { JUCE_ASIO_LOG (" Resetting"); - removeCurrentDriver(); + + if (! removeCurrentDriver()) + JUCE_ASIO_LOG ("** Driver crashed while being closed"); loadDriver(); String initError = initDriver(); @@ -640,8 +646,8 @@ public: BigInteger getActiveOutputChannels() const override { return currentChansOut; } BigInteger getActiveInputChannels() const override { return currentChansIn; } - int getOutputLatencyInSamples() override { return outputLatency + currentBlockSizeSamples / 4; } - int getInputLatencyInSamples() override { return inputLatency + currentBlockSizeSamples / 4; } + int getOutputLatencyInSamples() override { return outputLatency; } + int getInputLatencyInSamples() override { return inputLatency; } void start (AudioIODeviceCallback* callback) override { @@ -1075,28 +1081,32 @@ private: } } - static bool shouldReleaseObject (const String& driverName) + bool removeCurrentDriver() { - return driverName != "Yamaha Steinberg USB ASIO"; - } + bool releasedOK = true; - void removeCurrentDriver() - { if (asioObject != nullptr) { - char buffer[512] = {}; - asioObject->getDriverName (buffer); - - if (shouldReleaseObject (buffer)) + #if ! JUCE_MINGW + __try + #endif + { asioObject->Release(); + } + #if ! JUCE_MINGW + __except (EXCEPTION_EXECUTE_HANDLER) { releasedOK = false; } + #endif asioObject = nullptr; } + + return releasedOK; } bool loadDriver() { - removeCurrentDriver(); + if (! removeCurrentDriver()) + JUCE_ASIO_LOG ("** Driver crashed while being closed"); bool crashed = false; bool ok = tryCreatingDriver (crashed); @@ -1256,7 +1266,9 @@ private: { JUCE_ASIO_LOG_ERROR (error, err); disposeBuffers(); - removeCurrentDriver(); + + if (! removeCurrentDriver()) + JUCE_ASIO_LOG ("** Driver crashed while being closed"); } else { diff --git a/modules/juce_audio_devices/native/juce_win32_Midi.cpp b/modules/juce_audio_devices/native/juce_win32_Midi.cpp index ae2a9683..5a39111a 100644 --- a/modules/juce_audio_devices/native/juce_win32_Midi.cpp +++ b/modules/juce_audio_devices/native/juce_win32_Midi.cpp @@ -716,15 +716,17 @@ public: //============================================================================== WinRTMidiService() { - if (! WinRTWrapper::getInstance()->isInitialised()) + auto* wrtWrapper = WinRTWrapper::getInstance(); + + if (! wrtWrapper->isInitialised()) throw std::runtime_error ("Failed to initialise the WinRT wrapper"); - midiInFactory = WinRTWrapper::getInstance()->getWRLFactory (&RuntimeClass_Windows_Devices_Midi_MidiInPort[0]); + midiInFactory = wrtWrapper->getWRLFactory (&RuntimeClass_Windows_Devices_Midi_MidiInPort[0]); if (midiInFactory == nullptr) throw std::runtime_error ("Failed to create midi in factory"); - midiOutFactory = WinRTWrapper::getInstance()->getWRLFactory (&RuntimeClass_Windows_Devices_Midi_MidiOutPort[0]); + midiOutFactory = wrtWrapper->getWRLFactory (&RuntimeClass_Windows_Devices_Midi_MidiOutPort[0]); if (midiOutFactory == nullptr) throw std::runtime_error ("Failed to create midi out factory"); @@ -784,16 +786,24 @@ private: bool attach (HSTRING deviceSelector, DeviceInformationKind infoKind) { - auto deviceInfoFactory = WinRTWrapper::getInstance()->getWRLFactory (&RuntimeClass_Windows_Devices_Enumeration_DeviceInformation[0]); + auto* wrtWrapper = WinRTWrapper::getInstanceWithoutCreating(); + + if (wrtWrapper == nullptr) + { + JUCE_WINRT_MIDI_LOG ("Failed to get the WinRTWrapper singleton!"); + return false; + } + + auto deviceInfoFactory = wrtWrapper->getWRLFactory (&RuntimeClass_Windows_Devices_Enumeration_DeviceInformation[0]); if (deviceInfoFactory == nullptr) return false; // A quick way of getting an IVector... - auto requestedProperties = [] + auto requestedProperties = [wrtWrapper] { - auto devicePicker = WinRTWrapper::getInstance()->activateInstance (&RuntimeClass_Windows_Devices_Enumeration_DevicePicker[0], - __uuidof (IDevicePicker)); + auto devicePicker = wrtWrapper->activateInstance (&RuntimeClass_Windows_Devices_Enumeration_DevicePicker[0], + __uuidof (IDevicePicker)); jassert (devicePicker != nullptr); IVector* result; @@ -806,9 +816,9 @@ private: return result; }(); - StringArray propertyKeys = { "System.Devices.ContainerId", - "System.Devices.Aep.ContainerId", - "System.Devices.Aep.IsConnected" }; + StringArray propertyKeys ("System.Devices.ContainerId", + "System.Devices.Aep.ContainerId", + "System.Devices.Aep.IsConnected"); for (auto& key : propertyKeys) { @@ -994,7 +1004,7 @@ private: Callback> ( [handlerPtr](IDeviceWatcher*, IDeviceInformationUpdate* infoUpdate) { return handlerPtr->updateDevice (infoUpdate); } ).Get(), - &deviceRemovedToken); + &deviceUpdatedToken); watcher->Start(); } @@ -1045,7 +1055,15 @@ private: return S_OK; } - auto deviceID = WinRTWrapper::getInstance()->hStringToString (deviceIDHst); + auto* wrtWrapper = WinRTWrapper::getInstanceWithoutCreating(); + + if (wrtWrapper == nullptr) + { + JUCE_WINRT_MIDI_LOG ("Failed to get the WinRTWrapper singleton!"); + return false; + } + + auto deviceID = wrtWrapper->hStringToString (deviceIDHst); JUCE_WINRT_MIDI_LOG ("Detected paired BLE device: " << deviceID); if (auto* containerIDValue = getValueFromDeviceInfo ("System.Devices.Aep.ContainerId", addedDeviceInfo)) @@ -1082,7 +1100,15 @@ private: return S_OK; } - auto removedDeviceId = WinRTWrapper::getInstance()->hStringToString (removedDeviceIdHstr); + auto* wrtWrapper = WinRTWrapper::getInstanceWithoutCreating(); + + if (wrtWrapper == nullptr) + { + JUCE_WINRT_MIDI_LOG ("Failed to get the WinRTWrapper singleton!"); + return false; + } + + auto removedDeviceId = wrtWrapper->hStringToString (removedDeviceIdHstr); JUCE_WINRT_MIDI_LOG ("Removing BLE device: " << removedDeviceId); @@ -1112,7 +1138,15 @@ private: return S_OK; } - auto updatedDeviceId = WinRTWrapper::getInstance()->hStringToString (updatedDeviceIdHstr); + auto* wrtWrapper = WinRTWrapper::getInstanceWithoutCreating(); + + if (wrtWrapper == nullptr) + { + JUCE_WINRT_MIDI_LOG ("Failed to get the WinRTWrapper singleton!"); + return false; + } + + auto updatedDeviceId = wrtWrapper->hStringToString (updatedDeviceIdHstr); JUCE_WINRT_MIDI_LOG ("Updating BLE device: " << updatedDeviceId); @@ -1209,7 +1243,15 @@ private: return S_OK; } - info.deviceID = WinRTWrapper::getInstance()->hStringToString (deviceID); + auto* wrtWrapper = WinRTWrapper::getInstanceWithoutCreating(); + + if (wrtWrapper == nullptr) + { + JUCE_WINRT_MIDI_LOG ("Failed to get the WinRTWrapper singleton!"); + return false; + } + + info.deviceID = wrtWrapper->hStringToString (deviceID); JUCE_WINRT_MIDI_LOG ("Detected MIDI device: " << info.deviceID); @@ -1235,7 +1277,7 @@ private: return S_OK; } - info.name = WinRTWrapper::getInstance()->hStringToString (name); + info.name = wrtWrapper->hStringToString (name); boolean isDefault = false; hr = addedDeviceInfo->get_IsDefault (&isDefault); @@ -1269,7 +1311,15 @@ private: return S_OK; } - auto removedDeviceId = WinRTWrapper::getInstance()->hStringToString (removedDeviceIdHstr); + auto* wrtWrapper = WinRTWrapper::getInstanceWithoutCreating(); + + if (wrtWrapper == nullptr) + { + JUCE_WINRT_MIDI_LOG ("Failed to get the WinRTWrapper singleton!"); + return false; + } + + auto removedDeviceId = wrtWrapper->hStringToString (removedDeviceIdHstr); JUCE_WINRT_MIDI_LOG ("Removing MIDI device: " << removedDeviceId); @@ -1408,8 +1458,8 @@ private: } ).Get()); - // We need to use a timout here, rather than waiting indefinitely, as the - // WinRT API can occaisonally hang! + // We need to use a timeout here, rather than waiting indefinitely, as the + // WinRT API can occasionally hang! portOpened.wait (2000); } @@ -1674,7 +1724,12 @@ private: if (midiPort == nullptr) throw std::runtime_error ("Timed out waiting for midi output port creation"); - auto bufferFactory = WinRTWrapper::getInstance()->getWRLFactory (&RuntimeClass_Windows_Storage_Streams_Buffer[0]); + auto* wrtWrapper = WinRTWrapper::getInstanceWithoutCreating(); + + if (wrtWrapper == nullptr) + throw std::runtime_error ("Failed to get the WinRTWrapper singleton!"); + + auto bufferFactory = wrtWrapper->getWRLFactory (&RuntimeClass_Windows_Storage_Streams_Buffer[0]); if (bufferFactory == nullptr) throw std::runtime_error ("Failed to create output buffer factory"); @@ -1739,13 +1794,15 @@ private: //============================================================================== //============================================================================== -extern RTL_OSVERSIONINFOW getWindowsVersionInfo(); +#if ! JUCE_MINGW + extern RTL_OSVERSIONINFOW getWindowsVersionInfo(); +#endif struct MidiService : public DeletedAtShutdown { MidiService() { - #if JUCE_USE_WINRT_MIDI + #if JUCE_USE_WINRT_MIDI && ! JUCE_MINGW #if ! JUCE_FORCE_WINRT_MIDI auto windowsVersionInfo = getWindowsVersionInfo(); if (windowsVersionInfo.dwMajorVersion >= 10 && windowsVersionInfo.dwBuildNumber >= 17763) diff --git a/modules/juce_audio_devices/sources/juce_AudioSourcePlayer.h b/modules/juce_audio_devices/sources/juce_AudioSourcePlayer.h index 3f5a87d3..f1356022 100644 --- a/modules/juce_audio_devices/sources/juce_AudioSourcePlayer.h +++ b/modules/juce_audio_devices/sources/juce_AudioSourcePlayer.h @@ -105,7 +105,8 @@ private: float* outputChans[128]; const float* inputChans[128]; AudioBuffer tempBuffer; - float lastGain = 1.0f, gain = 1.0f; + float lastGain = 1.0f; + std::atomic gain { 1.0f }; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioSourcePlayer) }; diff --git a/modules/juce_audio_formats/codecs/juce_CoreAudioFormat.cpp b/modules/juce_audio_formats/codecs/juce_CoreAudioFormat.cpp index 330b86b2..dd6737a8 100644 --- a/modules/juce_audio_formats/codecs/juce_CoreAudioFormat.cpp +++ b/modules/juce_audio_formats/codecs/juce_CoreAudioFormat.cpp @@ -352,9 +352,9 @@ public: auto status = AudioFileOpenWithCallbacks (this, &readCallback, - nullptr, // write needs to be null to avoid permisisions errors + nullptr, // write needs to be null to avoid permissions errors &getSizeCallback, - nullptr, // setSize needs to be null to avoid permisisions errors + nullptr, // setSize needs to be null to avoid permissions errors 0, // AudioFileTypeID inFileTypeHint &audioFileID); if (status == noErr) @@ -616,7 +616,7 @@ public: : UnitTest ("Core Audio Layout <-> JUCE channel layout conversion", UnitTestCategories::audio) {} - // some ambisonic tags which are not explicitely defined + // some ambisonic tags which are not explicitly defined enum { kAudioChannelLayoutTag_HOA_ACN_SN3D_0Order = (190U<<16) | 1, diff --git a/modules/juce_audio_formats/codecs/juce_WavAudioFormat.cpp b/modules/juce_audio_formats/codecs/juce_WavAudioFormat.cpp index a2459c6d..3515786a 100644 --- a/modules/juce_audio_formats/codecs/juce_WavAudioFormat.cpp +++ b/modules/juce_audio_formats/codecs/juce_WavAudioFormat.cpp @@ -1052,8 +1052,15 @@ public: } else if (chunkType == chunkName ("data")) { - if (! isRF64) // data size is expected to be -1, actual data size is in ds64 chunk + if (isRF64) + { + if (dataLength > 0) + chunkEnd = input->getPosition() + dataLength + (dataLength & 1); + } + else + { dataLength = length; + } dataChunkStart = input->getPosition(); lengthInSamples = (bytesPerFrame > 0) ? (dataLength / bytesPerFrame) : 0; @@ -1349,7 +1356,7 @@ public: { // failed to write to disk, so let's try writing the header. // If it's just run out of disk space, then if it does manage - // to write the header, we'll still have a useable file.. + // to write the header, we'll still have a usable file.. writeHeader(); writeFailed = true; return false; diff --git a/modules/juce_audio_formats/codecs/juce_WindowsMediaAudioFormat.cpp b/modules/juce_audio_formats/codecs/juce_WindowsMediaAudioFormat.cpp index 01688937..34744425 100644 --- a/modules/juce_audio_formats/codecs/juce_WindowsMediaAudioFormat.cpp +++ b/modules/juce_audio_formats/codecs/juce_WindowsMediaAudioFormat.cpp @@ -206,7 +206,7 @@ public: if (hasJumped) bufferedRange.setStart ((int64) ((sampleTime * (int64) sampleRate) / 10000000)); else - bufferedRange.setStart (bufferedRange.getEnd()); // (because the positions returned often aren't continguous) + bufferedRange.setStart (bufferedRange.getEnd()); // (because the positions returned often aren't contiguous) bufferedRange.setLength ((int64) (dataLength / stride)); diff --git a/modules/juce_audio_formats/format/juce_AudioFormat.h b/modules/juce_audio_formats/format/juce_AudioFormat.h index dd6bacca..d3008572 100644 --- a/modules/juce_audio_formats/format/juce_AudioFormat.h +++ b/modules/juce_audio_formats/format/juce_AudioFormat.h @@ -132,9 +132,7 @@ public: to try to open a different format, etc @param sampleRateToUse the sample rate for the file, which must be one of the ones returned by getPossibleSampleRates() - @param numberOfChannels the number of channels - this must be either 1 or 2, and - the choice will depend on the results of canDoMono() and - canDoStereo() + @param numberOfChannels the number of channels @param bitsPerSample the bits per sample to use - this must be one of the values returned by getPossibleBitDepths() @param metadataValues a set of metadata values that the writer should try to write diff --git a/modules/juce_audio_formats/juce_audio_formats.h b/modules/juce_audio_formats/juce_audio_formats.h index 179d89f8..54b30763 100644 --- a/modules/juce_audio_formats/juce_audio_formats.h +++ b/modules/juce_audio_formats/juce_audio_formats.h @@ -24,6 +24,7 @@ ============================================================================== */ + /******************************************************************************* The block below describes the properties of this module, and is read by the Projucer to automatically generate project code that uses it. @@ -33,17 +34,17 @@ BEGIN_JUCE_MODULE_DECLARATION - ID: juce_audio_formats - vendor: juce - version: 5.4.5 - name: JUCE audio file format codecs - description: Classes for reading and writing various audio file formats. - website: http://www.juce.com/juce - license: GPL/Commercial - - dependencies: juce_audio_basics - OSXFrameworks: CoreAudio CoreMIDI QuartzCore AudioToolbox - iOSFrameworks: AudioToolbox QuartzCore + ID: juce_audio_formats + vendor: juce + version: 5.4.6 + name: JUCE audio file format codecs + description: Classes for reading and writing various audio file formats. + website: http://www.juce.com/juce + license: GPL/Commercial + + dependencies: juce_audio_basics + OSXFrameworks: CoreAudio CoreMIDI QuartzCore AudioToolbox + iOSFrameworks: AudioToolbox QuartzCore END_JUCE_MODULE_DECLARATION diff --git a/modules/juce_audio_plugin_client/AAX/juce_AAX_Wrapper.cpp b/modules/juce_audio_plugin_client/AAX/juce_AAX_Wrapper.cpp index adc374e1..9499b037 100644 --- a/modules/juce_audio_plugin_client/AAX/juce_AAX_Wrapper.cpp +++ b/modules/juce_audio_plugin_client/AAX/juce_AAX_Wrapper.cpp @@ -1004,7 +1004,12 @@ namespace AAXClasses info.timeInSeconds = info.timeInSamples / sampleRate; int64_t ticks = 0; - check (transport.GetCurrentTickPosition (&ticks)); + + if (info.isPlaying) + check (transport.GetCustomTickPosition (&ticks, info.timeInSamples)); + else + check (transport.GetCurrentTickPosition (&ticks)); + info.ppqPosition = ticks / 960000.0; info.isLooping = false; @@ -1652,7 +1657,7 @@ namespace AAXClasses if (isInAudioSuite()) { - // AudioSuite doesnt support multiple output buses + // AudioSuite doesn't support multiple output buses for (int i = 1; i < newLayout.outputBuses.size(); ++i) newLayout.outputBuses.getReference (i) = AudioChannelSet::disabled(); @@ -1823,7 +1828,7 @@ namespace AAXClasses if (LegacyAudioParameter::getParamID (aaxMeters[idx], false) == paramID) break; - // you sepecified a parameter id in your curve but the parameter does not have the meter + // you specified a parameter id in your curve but the parameter does not have the meter // category jassert (idx < aaxMeters.size()); return 'Metr' + static_cast (idx); diff --git a/modules/juce_audio_plugin_client/Standalone/juce_StandaloneFilterWindow.h b/modules/juce_audio_plugin_client/Standalone/juce_StandaloneFilterWindow.h index 0cc15378..2069d93e 100644 --- a/modules/juce_audio_plugin_client/Standalone/juce_StandaloneFilterWindow.h +++ b/modules/juce_audio_plugin_client/Standalone/juce_StandaloneFilterWindow.h @@ -255,36 +255,23 @@ public: { DialogWindow::LaunchOptions o; - int minNumInputs = std::numeric_limits::max(), maxNumInputs = 0, - minNumOutputs = std::numeric_limits::max(), maxNumOutputs = 0; - - auto updateMinAndMax = [] (int newValue, int& minValue, int& maxValue) - { - minValue = jmin (minValue, newValue); - maxValue = jmax (maxValue, newValue); - }; + int maxNumInputs = 0, maxNumOutputs = 0; if (channelConfiguration.size() > 0) { - auto defaultConfig = channelConfiguration.getReference (0); - updateMinAndMax ((int) defaultConfig.numIns, minNumInputs, maxNumInputs); - updateMinAndMax ((int) defaultConfig.numOuts, minNumOutputs, maxNumOutputs); + auto& defaultConfig = channelConfiguration.getReference (0); + + maxNumInputs = jmax (0, (int) defaultConfig.numIns); + maxNumOutputs = jmax (0, (int) defaultConfig.numOuts); } if (auto* bus = processor->getBus (true, 0)) - updateMinAndMax (bus->getDefaultLayout().size(), minNumInputs, maxNumInputs); + maxNumInputs = jmax (0, bus->getDefaultLayout().size()); if (auto* bus = processor->getBus (false, 0)) - updateMinAndMax (bus->getDefaultLayout().size(), minNumOutputs, maxNumOutputs); - - minNumInputs = jmin (minNumInputs, maxNumInputs); - minNumOutputs = jmin (minNumOutputs, maxNumOutputs); + maxNumOutputs = jmax (0, bus->getDefaultLayout().size()); - o.content.setOwned (new SettingsComponent (*this, deviceManager, - minNumInputs, - maxNumInputs, - minNumOutputs, - maxNumOutputs)); + o.content.setOwned (new SettingsComponent (*this, deviceManager, maxNumInputs, maxNumOutputs)); o.content->setSize (500, 550); o.dialogTitle = TRANS("Audio/MIDI Settings"); @@ -425,14 +412,12 @@ private: public: SettingsComponent (StandalonePluginHolder& pluginHolder, AudioDeviceManager& deviceManagerToUse, - int minAudioInputChannels, int maxAudioInputChannels, - int minAudioOutputChannels, int maxAudioOutputChannels) : owner (pluginHolder), deviceSelector (deviceManagerToUse, - minAudioInputChannels, maxAudioInputChannels, - minAudioOutputChannels, maxAudioOutputChannels, + 0, maxAudioInputChannels, + 0, maxAudioOutputChannels, true, (pluginHolder.processor.get() != nullptr && pluginHolder.processor->producesMidi()), true, false), diff --git a/modules/juce_audio_plugin_client/VST/juce_VST_Wrapper.cpp b/modules/juce_audio_plugin_client/VST/juce_VST_Wrapper.cpp index 9b9a7f9f..879c9066 100644 --- a/modules/juce_audio_plugin_client/VST/juce_VST_Wrapper.cpp +++ b/modules/juce_audio_plugin_client/VST/juce_VST_Wrapper.cpp @@ -38,21 +38,21 @@ #if JucePlugin_VersionCode < 0x010000 // Major < 0 - #if (JucePlugin_VersionCode & 0x00FF00) > (9 * 0x100) // check if Minor number exceeeds 9 + #if (JucePlugin_VersionCode & 0x00FF00) > (9 * 0x100) // check if Minor number exceeds 9 JUCE_COMPILER_WARNING ("When version has 'major' = 0, VST2 has trouble displaying 'minor' exceeding 9") #endif - #if (JucePlugin_VersionCode & 0xFF) > 9 // check if Bugfix number exceeeds 9 + #if (JucePlugin_VersionCode & 0xFF) > 9 // check if Bugfix number exceeds 9 JUCE_COMPILER_WARNING ("When version has 'major' = 0, VST2 has trouble displaying 'bugfix' exceeding 9") #endif #elif JucePlugin_VersionCode >= 0x650000 // Major >= 101 - #if (JucePlugin_VersionCode & 0x00FF00) > (99 * 0x100) // check if Minor number exceeeds 99 + #if (JucePlugin_VersionCode & 0x00FF00) > (99 * 0x100) // check if Minor number exceeds 99 JUCE_COMPILER_WARNING ("When version has 'major' > 100, VST2 has trouble displaying 'minor' exceeding 99") #endif - #if (JucePlugin_VersionCode & 0xFF) > 99 // check if Bugfix number exceeeds 99 + #if (JucePlugin_VersionCode & 0xFF) > 99 // check if Bugfix number exceeds 99 JUCE_COMPILER_WARNING ("When version has 'major' > 100, VST2 has trouble displaying 'bugfix' exceeding 99") #endif diff --git a/modules/juce_audio_plugin_client/VST/juce_VST_Wrapper.mm b/modules/juce_audio_plugin_client/VST/juce_VST_Wrapper.mm index da1fb989..3672ab73 100644 --- a/modules/juce_audio_plugin_client/VST/juce_VST_Wrapper.mm +++ b/modules/juce_audio_plugin_client/VST/juce_VST_Wrapper.mm @@ -230,7 +230,7 @@ void detachComponentFromWindowRefVST (Component* comp, void* window, bool isNSVi // The event loop needs to be run between closing the window and deleting the plugin, // presumably to let the cocoa objects get tidied up. Leaving out this line causes crashes // in Live when you delete the plugin with its window open. - // (Doing it this way rather than using a single longer timout means that we can guarantee + // (Doing it this way rather than using a single longer timeout means that we can guarantee // how many messages will be dispatched, which seems to be vital in Reaper) if (needToRunMessageLoop) for (int i = 20; --i >= 0;) diff --git a/modules/juce_audio_plugin_client/VST3/juce_VST3_Wrapper.cpp b/modules/juce_audio_plugin_client/VST3/juce_VST3_Wrapper.cpp index d94d022a..0947eb5f 100644 --- a/modules/juce_audio_plugin_client/VST3/juce_VST3_Wrapper.cpp +++ b/modules/juce_audio_plugin_client/VST3/juce_VST3_Wrapper.cpp @@ -423,19 +423,19 @@ public: { Param (JuceVST3EditController& editController, AudioProcessorParameter& p, Vst::ParamID vstParamID, Vst::UnitID vstUnitID, - bool isBypassParameter, bool forceLegacyParamIDs) + bool isBypassParameter) : owner (editController), param (p) { info.id = vstParamID; info.unitId = vstUnitID; - toString128 (info.title, param.getName (128)); - toString128 (info.shortTitle, param.getName (8)); - toString128 (info.units, param.getLabel()); + updateParameterInfo(); info.stepCount = (Steinberg::int32) 0; - if (! forceLegacyParamIDs && param.isDiscrete()) + #if ! JUCE_FORCE_LEGACY_PARAMETER_AUTOMATION_TYPE + if (param.isDiscrete()) + #endif { const int numSteps = param.getNumSteps(); info.stepCount = (Steinberg::int32) (numSteps > 0 && numSteps < 0x7fffffff ? numSteps - 1 : 0); @@ -458,6 +458,13 @@ public: virtual ~Param() override = default; + void updateParameterInfo() + { + toString128 (info.title, param.getName (128)); + toString128 (info.shortTitle, param.getName (8)); + toString128 (info.units, param.getLabel()); + } + bool setNormalized (Vst::ParamValue v) override { v = jlimit (0.0, 1.0, v); @@ -682,9 +689,13 @@ public: tresult PLUGIN_API getMidiControllerAssignment (Steinberg::int32 /*busIndex*/, Steinberg::int16 channel, Vst::CtrlNumber midiControllerNumber, Vst::ParamID& resultID) override { + #if JUCE_VST3_EMULATE_MIDI_CC_WITH_PARAMETERS resultID = midiControllerToParameter[channel][midiControllerNumber]; - return kResultTrue; // Returning false makes some hosts stop asking for further MIDI Controller Assignments + #else + ignoreUnused (channel, midiControllerNumber, resultID); + return kResultFalse; + #endif } // Converts an incoming parameter index to a MIDI controller: @@ -881,6 +892,12 @@ public: void audioProcessorChanged (AudioProcessor*) override { + auto numParameters = parameters.getParameterCount(); + + for (int32 i = 0; i < numParameters; ++i) + if (auto* param = dynamic_cast (parameters.getParameterByIndex (i))) + param->updateParameterInfo(); + if (auto* pluginInstance = getPluginInstance()) { if (pluginInstance->getNumPrograms() > 1) @@ -889,7 +906,7 @@ public: } if (componentHandler != nullptr && ! inSetupProcessing) - componentHandler->restartComponent (Vst::kLatencyChanged | Vst::kParamValuesChanged); + componentHandler->restartComponent (Vst::kLatencyChanged | Vst::kParamValuesChanged | Vst::kParamTitlesChanged); } void parameterValueChanged (int, float newValue) override @@ -950,12 +967,6 @@ private: if (parameters.getParameterCount() <= 0) { - #if JUCE_FORCE_USE_LEGACY_PARAM_IDS - const bool forceLegacyParamIDs = true; - #else - const bool forceLegacyParamIDs = false; - #endif - auto n = audioProcessor->getNumParameters(); for (int i = 0; i < n; ++i) @@ -966,7 +977,7 @@ private: auto unitID = JuceAudioProcessor::getUnitID (parameterGroup); parameters.addParameter (new Param (*this, *juceParam, vstParamID, unitID, - (vstParamID == audioProcessor->bypassParamID), forceLegacyParamIDs)); + (vstParamID == audioProcessor->bypassParamID))); } if (pluginInstance->getNumPrograms() > 1) @@ -1070,6 +1081,9 @@ private: component->addToDesktop (0, parent); component->setOpaque (true); component->setVisible (true); + #if JUCE_WIN_PER_MONITOR_DPI_AWARE + component->checkScaleFactorIsCorrect(); + #endif #else isNSView = (strcmp (type, kPlatformTypeNSView) == 0); macHostWindow = juce::attachComponentToWindowRefVST (component.get(), parent, isNSView); @@ -2423,7 +2437,7 @@ public: pluginInstance->setCurrentProgram (programValue); } #if JUCE_VST3_EMULATE_MIDI_CC_WITH_PARAMETERS - else if (juceVST3EditController->isMidiControllerParamID (vstParamID)) + else if (juceVST3EditController != nullptr && juceVST3EditController->isMidiControllerParamID (vstParamID)) addParameterChangeToMidiBuffer (offsetSamples, vstParamID, value); #endif else @@ -2567,6 +2581,10 @@ private: for (int bus = 0; bus < n && totalOutputChans < plugInOutputChannels; ++bus) { + if (auto* busObject = pluginInstance->getBus (false, bus)) + if (! busObject->isEnabled()) + continue; + if (bus < vstOutputs) { if (auto** const busChannels = getPointerForAudioBus (data.outputs[bus])) @@ -2608,6 +2626,10 @@ private: for (int bus = 0; bus < n && totalInputChans < plugInInputChannels; ++bus) { + if (auto* busObject = pluginInstance->getBus (true, bus)) + if (! busObject->isEnabled()) + continue; + if (bus < vstInputs) { if (auto** const busChannels = getPointerForAudioBus (data.inputs[bus])) diff --git a/modules/juce_audio_plugin_client/juce_audio_plugin_client.h b/modules/juce_audio_plugin_client/juce_audio_plugin_client.h index d884d0ac..95b70c23 100644 --- a/modules/juce_audio_plugin_client/juce_audio_plugin_client.h +++ b/modules/juce_audio_plugin_client/juce_audio_plugin_client.h @@ -24,6 +24,7 @@ ============================================================================== */ + /******************************************************************************* The block below describes the properties of this module, and is read by the Projucer to automatically generate project code that uses it. @@ -33,15 +34,15 @@ BEGIN_JUCE_MODULE_DECLARATION - ID: juce_audio_plugin_client - vendor: juce - version: 5.4.5 - name: JUCE audio plugin wrapper classes - description: Classes for building VST, VST3, AudioUnit, AAX and RTAS plugins. - website: http://www.juce.com/juce - license: GPL/Commercial + ID: juce_audio_plugin_client + vendor: juce + version: 5.4.6 + name: JUCE audio plugin wrapper classes + description: Classes for building VST, VST3, AudioUnit, AAX and RTAS plugins. + website: http://www.juce.com/juce + license: GPL/Commercial - dependencies: juce_gui_basics, juce_audio_basics, juce_audio_processors + dependencies: juce_gui_basics, juce_audio_basics, juce_audio_processors END_JUCE_MODULE_DECLARATION @@ -92,16 +93,30 @@ /** Config: JUCE_USE_STUDIO_ONE_COMPATIBLE_PARAMETERS Enable this if you want JUCE to use parameter ids which are compatible - with Studio One. Studio One ignores any parameter ids which are negative. + with Studio One, as Studio One ignores any parameter ids which are negative. Enabling this option will make JUCE generate only positive parameter ids. Note that if you have already released a plug-in prior to JUCE 4.3.0 then - enabling this will change your parameter ids making your plug-in - incompatible to old automation data. + enabling this will change your parameter ids, making your plug-in + incompatible with old automation data. */ #ifndef JUCE_USE_STUDIO_ONE_COMPATIBLE_PARAMETERS #define JUCE_USE_STUDIO_ONE_COMPATIBLE_PARAMETERS 1 #endif +/** Config: JUCE_AU_WRAPPERS_SAVE_PROGRAM_STATES + + Enable this if you want to receive get/setProgramStateInformation calls, + instead of get/setStateInformation calls, from the AU and AUv3 plug-in + wrappers. In JUCE version 5.4.5 and earlier this was the default behaviour, + so if you have modified the default implementations of get/setProgramStateInformation + (where the default implementations simply call through to get/setStateInformation) + then you may need to enable this configuration option to maintain backwards + compatibility with previously saved state. +*/ +#ifndef JUCE_AU_WRAPPERS_SAVE_PROGRAM_STATES + #define JUCE_AU_WRAPPERS_SAVE_PROGRAM_STATES 0 +#endif + /** Config: JUCE_STANDALONE_FILTER_WINDOW_USE_KIOSK_MODE Enable this if you want your standalone plugin window to use kiosk mode. diff --git a/modules/juce_audio_plugin_client/juce_audio_plugin_client_AU.r b/modules/juce_audio_plugin_client/juce_audio_plugin_client_AU.r index 4fcd685e..72623a82 100644 --- a/modules/juce_audio_plugin_client/juce_audio_plugin_client_AU.r +++ b/modules/juce_audio_plugin_client/juce_audio_plugin_client_AU.r @@ -25,7 +25,7 @@ */ #define UseExtendedThingResource 1 -#include +#include //============================================================================== /* The AppConfig.h file should be a file in your project, containing info to describe the diff --git a/modules/juce_audio_plugin_client/juce_audio_plugin_client_AU_2.mm b/modules/juce_audio_plugin_client/juce_audio_plugin_client_AU_2.mm index 2edb687f..5b83f671 100644 --- a/modules/juce_audio_plugin_client/juce_audio_plugin_client_AU_2.mm +++ b/modules/juce_audio_plugin_client/juce_audio_plugin_client_AU_2.mm @@ -24,6 +24,8 @@ ============================================================================== */ +#if JucePlugin_Build_AU + #ifdef __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wparentheses" @@ -43,6 +45,9 @@ #if __has_warning("-Wnullable-to-nonnull-conversion") #pragma clang diagnostic ignored "-Wnullable-to-nonnull-conversion" #endif + #if __has_warning("-Wignored-qualifiers") + #pragma clang diagnostic ignored "-Wignored-qualifiers" + #endif #endif // From MacOS 10.13 and iOS 11 Apple has (sensibly!) stopped defining a whole @@ -81,3 +86,5 @@ #ifdef __clang__ #pragma clang diagnostic pop #endif + +#endif diff --git a/modules/juce_audio_plugin_client/juce_audio_plugin_client_Standalone.cpp b/modules/juce_audio_plugin_client/juce_audio_plugin_client_Standalone.cpp index bd8ad922..19fa722a 100644 --- a/modules/juce_audio_plugin_client/juce_audio_plugin_client_Standalone.cpp +++ b/modules/juce_audio_plugin_client/juce_audio_plugin_client_Standalone.cpp @@ -24,6 +24,8 @@ ============================================================================== */ +#if JucePlugin_Build_Standalone + #if ! JUCE_MODULE_AVAILABLE_juce_audio_utils #error To compile AudioUnitv3 and/or Standalone plug-ins, you need to add the juce_audio_utils and juce_audio_devices modules! #endif @@ -42,3 +44,5 @@ #endif JUCE_MAIN_FUNCTION_DEFINITION + +#endif diff --git a/modules/juce_audio_plugin_client/utility/juce_PluginHostType.h b/modules/juce_audio_plugin_client/utility/juce_PluginHostType.h index 3607a441..11f5d8ff 100644 --- a/modules/juce_audio_plugin_client/utility/juce_PluginHostType.h +++ b/modules/juce_audio_plugin_client/utility/juce_PluginHostType.h @@ -77,6 +77,7 @@ public: MuseReceptorGeneric, /**< Represents Muse Receptor. */ pluginval, /**< Represents pluginval. */ Reaper, /**< Represents Cockos Reaper. */ + Reason, /**< Represents Reason. */ Renoise, /**< Represents Renoise. */ SADiE, /**< Represents SADiE. */ SteinbergCubase4, /**< Represents Steinberg Cubase 4. */ @@ -89,6 +90,7 @@ public: SteinbergCubase9, /**< Represents Steinberg Cubase 9. */ SteinbergCubase9_5, /**< Represents Steinberg Cubase 9.5. */ SteinbergCubase10, /**< Represents Steinberg Cubase 10. */ + SteinbergCubase10_5, /**< Represents Steinberg Cubase 10.5. */ SteinbergCubaseGeneric, /**< Represents Steinberg Cubase. */ SteinbergNuendo3, /**< Represents Steinberg Nuendo 3. */ SteinbergNuendo4, /**< Represents Steinberg Nuendo 4. */ @@ -105,6 +107,7 @@ public: TracktionGeneric, /**< Represents Tracktion. */ TracktionWaveform, /**< Represents Tracktion Waveform. */ VBVSTScanner, /**< Represents VB Audio VST Scanner. */ + ViennaEnsemblePro, /**< Represents Vienna Ensemble Pro. */ WaveBurner /**< Represents Apple WaveBurner. */ }; @@ -112,7 +115,8 @@ public: //============================================================================== /** Returns true if the host is any version of Ableton Live. */ - bool isAbletonLive() const noexcept { return type == AbletonLive6 || type == AbletonLive7 || type == AbletonLive8 || type == AbletonLive9 || type == AbletonLive10 || type == AbletonLiveGeneric; } + bool isAbletonLive() const noexcept { return type == AbletonLive6 || type == AbletonLive7 || type == AbletonLive8 + || type == AbletonLive9 || type == AbletonLive10 || type == AbletonLiveGeneric; } /** Returns true if the host is Adobe Audition. */ bool isAdobeAudition() const noexcept { return type == AdobeAudition; } /** Returns true if the host is Ardour. */ @@ -120,7 +124,9 @@ public: /** Returns true if the host is Bitwig Studio. */ bool isBitwigStudio() const noexcept { return type == BitwigStudio; } /** Returns true if the host is any version of Steinberg Cubase. */ - bool isCubase() const noexcept { return type == SteinbergCubase4 || type == SteinbergCubase5 || type == SteinbergCubase5Bridged || type == SteinbergCubase6 || type == SteinbergCubase7 || type == SteinbergCubase8 || type == SteinbergCubase8_5 || type == SteinbergCubase9 || type == SteinbergCubase9_5 || type == SteinbergCubase10 || type == SteinbergCubaseGeneric; } + bool isCubase() const noexcept { return type == SteinbergCubase4 || type == SteinbergCubase5 || type == SteinbergCubase5Bridged || type == SteinbergCubase6 + || type == SteinbergCubase7 || type == SteinbergCubase8 || type == SteinbergCubase8_5 || type == SteinbergCubase9 + || type == SteinbergCubase9_5 || type == SteinbergCubase10 || type == SteinbergCubase10_5 || type == SteinbergCubaseGeneric; } /** Returns true if the host is Steinberg Cubase 7 or later. */ bool isCubase7orLater() const noexcept { return isCubase() && ! (type == SteinbergCubase4 || type == SteinbergCubase5 || type == SteinbergCubase6); } /** Returns true if the host is Steinberg Cubase 5 Bridged. */ @@ -155,6 +161,8 @@ public: bool isReceptor() const noexcept { return type == MuseReceptorGeneric; } /** Returns true if the host is Cockos Reaper. */ bool isReaper() const noexcept { return type == Reaper; } + /** Returns true if the host is Reason. */ + bool isReason() const noexcept { return type == Reason; } /** Returns true if the host is Renoise. */ bool isRenoise() const noexcept { return type == Renoise; } /** Returns true if the host is SADiE. */ @@ -177,6 +185,8 @@ public: bool isTracktionWaveform() const noexcept { return type == TracktionWaveform; } /** Returns true if the host is VB Audio VST Scanner. */ bool isVBVSTScanner() const noexcept { return type == VBVSTScanner; } + /** Returns true if the host is Vienna Ensemble Pro. */ + bool isViennaEnsemblePro() const noexcept { return type == ViennaEnsemblePro; } /** Returns true if the host is Apple WaveBurner. */ bool isWaveBurner() const noexcept { return type == WaveBurner; } /** Returns true if the host is any version of Steinberg WaveLab. */ @@ -218,6 +228,7 @@ public: case MergingPyramix: return "Pyramix"; case MuseReceptorGeneric: return "Muse Receptor"; case Reaper: return "Reaper"; + case Reason: return "Reason"; case Renoise: return "Renoise"; case SADiE: return "SADiE"; case SteinbergCubase4: return "Steinberg Cubase 4"; @@ -230,6 +241,7 @@ public: case SteinbergCubase9: return "Steinberg Cubase 9"; case SteinbergCubase9_5: return "Steinberg Cubase 9.5"; case SteinbergCubase10: return "Steinberg Cubase 10"; + case SteinbergCubase10_5: return "Steinberg Cubase 10.5"; case SteinbergCubaseGeneric: return "Steinberg Cubase"; case SteinbergNuendo3: return "Steinberg Nuendo 3"; case SteinbergNuendo4: return "Steinberg Nuendo 4"; @@ -246,6 +258,7 @@ public: case TracktionGeneric: return "Tracktion"; case TracktionWaveform: return "Tracktion Waveform"; case VBVSTScanner: return "VBVSTScanner"; + case ViennaEnsemblePro: return "Vienna Ensemble Pro"; case WaveBurner: return "WaveBurner"; default: break; } @@ -299,107 +312,114 @@ private: auto hostFilename = File (hostPath).getFileName(); #if JUCE_MAC - if (hostPath.containsIgnoreCase ("Final Cut Pro.app")) return FinalCut; - if (hostPath.containsIgnoreCase ("Final Cut Pro Trial.app")) return FinalCut; - if (hostPath.containsIgnoreCase ("Live 6.")) return AbletonLive6; - if (hostPath.containsIgnoreCase ("Live 7.")) return AbletonLive7; - if (hostPath.containsIgnoreCase ("Live 8.")) return AbletonLive8; - if (hostPath.containsIgnoreCase ("Live 9.")) return AbletonLive9; - if (hostPath.containsIgnoreCase ("Live 10.")) return AbletonLive10; - if (hostFilename.containsIgnoreCase ("Live")) return AbletonLiveGeneric; - if (hostFilename.containsIgnoreCase ("Adobe Premiere")) return AdobePremierePro; - if (hostFilename.containsIgnoreCase ("GarageBand")) return AppleGarageBand; - if (hostFilename.containsIgnoreCase ("Logic")) return AppleLogic; - if (hostFilename.containsIgnoreCase ("MainStage")) return AppleMainStage; - if (hostFilename.containsIgnoreCase ("Pro Tools")) return AvidProTools; - if (hostFilename.containsIgnoreCase ("Nuendo 3")) return SteinbergNuendo3; - if (hostFilename.containsIgnoreCase ("Nuendo 4")) return SteinbergNuendo4; - if (hostFilename.containsIgnoreCase ("Nuendo 5")) return SteinbergNuendo5; - if (hostFilename.containsIgnoreCase ("Nuendo")) return SteinbergNuendoGeneric; - if (hostFilename.containsIgnoreCase ("Cubase 4")) return SteinbergCubase4; - if (hostFilename.containsIgnoreCase ("Cubase 5")) return SteinbergCubase5; - if (hostFilename.containsIgnoreCase ("Cubase 6")) return SteinbergCubase6; - if (hostFilename.containsIgnoreCase ("Cubase 7")) return SteinbergCubase7; - if (hostPath.containsIgnoreCase ("Cubase 8.app")) return SteinbergCubase8; - if (hostPath.containsIgnoreCase ("Cubase 8.5.app")) return SteinbergCubase8_5; - if (hostPath.containsIgnoreCase ("Cubase 9.app")) return SteinbergCubase9; - if (hostPath.containsIgnoreCase ("Cubase 9.5.app")) return SteinbergCubase9_5; - if (hostPath.containsIgnoreCase ("Cubase 10.app")) return SteinbergCubase10; - if (hostFilename.containsIgnoreCase ("Cubase")) return SteinbergCubaseGeneric; - if (hostPath.containsIgnoreCase ("Wavelab 7")) return SteinbergWavelab7; - if (hostPath.containsIgnoreCase ("Wavelab 8")) return SteinbergWavelab8; - if (hostFilename.containsIgnoreCase ("Wavelab")) return SteinbergWavelabGeneric; - if (hostFilename.containsIgnoreCase ("WaveBurner")) return WaveBurner; - if (hostPath.containsIgnoreCase ("Digital Performer")) return DigitalPerformer; - if (hostFilename.containsIgnoreCase ("reaper")) return Reaper; - if (hostPath.containsIgnoreCase ("Studio One")) return StudioOne; - if (hostFilename.startsWithIgnoreCase ("Waveform")) return TracktionWaveform; - if (hostPath.containsIgnoreCase ("Tracktion 3")) return Tracktion3; - if (hostFilename.containsIgnoreCase ("Tracktion")) return TracktionGeneric; - if (hostFilename.containsIgnoreCase ("Renoise")) return Renoise; - if (hostFilename.containsIgnoreCase ("Resolve")) return DaVinciResolve; - if (hostFilename.startsWith ("Bitwig")) return BitwigStudio; - if (hostFilename.containsIgnoreCase ("OsxFL")) return FruityLoops; - if (hostFilename.containsIgnoreCase ("pluginval")) return pluginval; - if (hostFilename.containsIgnoreCase ("AudioPluginHost")) return JUCEPluginHost; + if (hostPath.containsIgnoreCase ("Final Cut Pro.app")) return FinalCut; + if (hostPath.containsIgnoreCase ("Final Cut Pro Trial.app")) return FinalCut; + if (hostPath.containsIgnoreCase ("Live 6")) return AbletonLive6; + if (hostPath.containsIgnoreCase ("Live 7")) return AbletonLive7; + if (hostPath.containsIgnoreCase ("Live 8")) return AbletonLive8; + if (hostPath.containsIgnoreCase ("Live 9")) return AbletonLive9; + if (hostPath.containsIgnoreCase ("Live 10")) return AbletonLive10; + if (hostFilename.containsIgnoreCase ("Live")) return AbletonLiveGeneric; + if (hostFilename.containsIgnoreCase ("Adobe Premiere")) return AdobePremierePro; + if (hostFilename.containsIgnoreCase ("GarageBand")) return AppleGarageBand; + if (hostFilename.containsIgnoreCase ("Logic")) return AppleLogic; + if (hostFilename.containsIgnoreCase ("MainStage")) return AppleMainStage; + if (hostFilename.containsIgnoreCase ("Pro Tools")) return AvidProTools; + if (hostFilename.containsIgnoreCase ("Nuendo 3")) return SteinbergNuendo3; + if (hostFilename.containsIgnoreCase ("Nuendo 4")) return SteinbergNuendo4; + if (hostFilename.containsIgnoreCase ("Nuendo 5")) return SteinbergNuendo5; + if (hostFilename.containsIgnoreCase ("Nuendo")) return SteinbergNuendoGeneric; + if (hostFilename.containsIgnoreCase ("Cubase 4")) return SteinbergCubase4; + if (hostFilename.containsIgnoreCase ("Cubase 5")) return SteinbergCubase5; + if (hostFilename.containsIgnoreCase ("Cubase 6")) return SteinbergCubase6; + if (hostFilename.containsIgnoreCase ("Cubase 7")) return SteinbergCubase7; + if (hostPath.containsIgnoreCase ("Cubase 8.app")) return SteinbergCubase8; + if (hostPath.containsIgnoreCase ("Cubase 8.5.app")) return SteinbergCubase8_5; + if (hostPath.containsIgnoreCase ("Cubase 9.app")) return SteinbergCubase9; + if (hostPath.containsIgnoreCase ("Cubase 9.5.app")) return SteinbergCubase9_5; + if (hostPath.containsIgnoreCase ("Cubase 10.app")) return SteinbergCubase10; + if (hostPath.containsIgnoreCase ("Cubase 10.5.app")) return SteinbergCubase10_5; + if (hostFilename.containsIgnoreCase ("Cubase")) return SteinbergCubaseGeneric; + if (hostPath.containsIgnoreCase ("Wavelab 7")) return SteinbergWavelab7; + if (hostPath.containsIgnoreCase ("Wavelab 8")) return SteinbergWavelab8; + if (hostFilename.containsIgnoreCase ("Wavelab")) return SteinbergWavelabGeneric; + if (hostFilename.containsIgnoreCase ("WaveBurner")) return WaveBurner; + if (hostPath.containsIgnoreCase ("Digital Performer")) return DigitalPerformer; + if (hostFilename.containsIgnoreCase ("reaper")) return Reaper; + if (hostFilename.containsIgnoreCase ("Reason")) return Reason; + if (hostPath.containsIgnoreCase ("Studio One")) return StudioOne; + if (hostFilename.startsWithIgnoreCase ("Waveform")) return TracktionWaveform; + if (hostPath.containsIgnoreCase ("Tracktion 3")) return Tracktion3; + if (hostFilename.containsIgnoreCase ("Tracktion")) return TracktionGeneric; + if (hostFilename.containsIgnoreCase ("Renoise")) return Renoise; + if (hostFilename.containsIgnoreCase ("Resolve")) return DaVinciResolve; + if (hostFilename.startsWith ("Bitwig")) return BitwigStudio; + if (hostFilename.containsIgnoreCase ("OsxFL")) return FruityLoops; + if (hostFilename.containsIgnoreCase ("pluginval")) return pluginval; + if (hostFilename.containsIgnoreCase ("AudioPluginHost")) return JUCEPluginHost; + if (hostFilename.containsIgnoreCase ("Vienna Ensemble Pro")) return ViennaEnsemblePro; #elif JUCE_WINDOWS - if (hostFilename.containsIgnoreCase ("Live 6.")) return AbletonLive6; - if (hostFilename.containsIgnoreCase ("Live 7.")) return AbletonLive7; - if (hostFilename.containsIgnoreCase ("Live 8.")) return AbletonLive8; - if (hostFilename.containsIgnoreCase ("Live 9.")) return AbletonLive9; - if (hostFilename.containsIgnoreCase ("Live 10.")) return AbletonLive10; - if (hostFilename.containsIgnoreCase ("Live ")) return AbletonLiveGeneric; - if (hostFilename.containsIgnoreCase ("Audition")) return AdobeAudition; - if (hostFilename.containsIgnoreCase ("Adobe Premiere")) return AdobePremierePro; - if (hostFilename.containsIgnoreCase ("ProTools")) return AvidProTools; - if (hostPath.containsIgnoreCase ("SONAR 8")) return CakewalkSonar8; - if (hostFilename.containsIgnoreCase ("SONAR")) return CakewalkSonarGeneric; - if (hostFilename.containsIgnoreCase ("Cakewalk.exe")) return CakewalkByBandlab; - if (hostFilename.containsIgnoreCase ("GarageBand")) return AppleGarageBand; - if (hostFilename.containsIgnoreCase ("Logic")) return AppleLogic; - if (hostFilename.containsIgnoreCase ("MainStage")) return AppleMainStage; - if (hostFilename.startsWithIgnoreCase ("Waveform")) return TracktionWaveform; - if (hostPath.containsIgnoreCase ("Tracktion 3")) return Tracktion3; - if (hostFilename.containsIgnoreCase ("Tracktion")) return TracktionGeneric; - if (hostFilename.containsIgnoreCase ("reaper")) return Reaper; - if (hostFilename.containsIgnoreCase ("Cubase4")) return SteinbergCubase4; - if (hostFilename.containsIgnoreCase ("Cubase5")) return SteinbergCubase5; - if (hostFilename.containsIgnoreCase ("Cubase6")) return SteinbergCubase6; - if (hostFilename.containsIgnoreCase ("Cubase7")) return SteinbergCubase7; - if (hostFilename.containsIgnoreCase ("Cubase8.exe")) return SteinbergCubase8; - if (hostFilename.containsIgnoreCase ("Cubase8.5.exe")) return SteinbergCubase8_5; + if (hostFilename.containsIgnoreCase ("Live 6")) return AbletonLive6; + if (hostFilename.containsIgnoreCase ("Live 7")) return AbletonLive7; + if (hostFilename.containsIgnoreCase ("Live 8")) return AbletonLive8; + if (hostFilename.containsIgnoreCase ("Live 9")) return AbletonLive9; + if (hostFilename.containsIgnoreCase ("Live 10")) return AbletonLive10; + if (hostFilename.containsIgnoreCase ("Live ")) return AbletonLiveGeneric; + if (hostFilename.containsIgnoreCase ("Audition")) return AdobeAudition; + if (hostFilename.containsIgnoreCase ("Adobe Premiere")) return AdobePremierePro; + if (hostFilename.containsIgnoreCase ("ProTools")) return AvidProTools; + if (hostPath.containsIgnoreCase ("SONAR 8")) return CakewalkSonar8; + if (hostFilename.containsIgnoreCase ("SONAR")) return CakewalkSonarGeneric; + if (hostFilename.containsIgnoreCase ("Cakewalk.exe")) return CakewalkByBandlab; + if (hostFilename.containsIgnoreCase ("GarageBand")) return AppleGarageBand; + if (hostFilename.containsIgnoreCase ("Logic")) return AppleLogic; + if (hostFilename.containsIgnoreCase ("MainStage")) return AppleMainStage; + if (hostFilename.startsWithIgnoreCase ("Waveform")) return TracktionWaveform; + if (hostPath.containsIgnoreCase ("Tracktion 3")) return Tracktion3; + if (hostFilename.containsIgnoreCase ("Tracktion")) return TracktionGeneric; + if (hostFilename.containsIgnoreCase ("reaper")) return Reaper; + if (hostFilename.containsIgnoreCase ("Cubase4")) return SteinbergCubase4; + if (hostFilename.containsIgnoreCase ("Cubase5")) return SteinbergCubase5; + if (hostFilename.containsIgnoreCase ("Cubase6")) return SteinbergCubase6; + if (hostFilename.containsIgnoreCase ("Cubase7")) return SteinbergCubase7; + if (hostFilename.containsIgnoreCase ("Cubase8.exe")) return SteinbergCubase8; + if (hostFilename.containsIgnoreCase ("Cubase8.5.exe")) return SteinbergCubase8_5; // Later version of Cubase scan plug-ins with a separate executable "vst2xscanner" if (hostFilename.containsIgnoreCase ("Cubase9.5.exe") - || hostPath.containsIgnoreCase ("Cubase 9.5")) return SteinbergCubase9_5; + || hostPath.containsIgnoreCase ("Cubase 9.5")) return SteinbergCubase9_5; if (hostFilename.containsIgnoreCase ("Cubase9.exe") - || hostPath.containsIgnoreCase ("Cubase 9")) return SteinbergCubase9; + || hostPath.containsIgnoreCase ("Cubase 9")) return SteinbergCubase9; + if (hostFilename.containsIgnoreCase ("Cubase10.5.exe") + || hostPath.containsIgnoreCase ("Cubase 10.5")) return SteinbergCubase10_5; if (hostFilename.containsIgnoreCase ("Cubase10.exe") - || hostPath.containsIgnoreCase ("Cubase 10")) return SteinbergCubase10; - if (hostFilename.containsIgnoreCase ("Cubase")) return SteinbergCubaseGeneric; - if (hostFilename.containsIgnoreCase ("VSTBridgeApp")) return SteinbergCubase5Bridged; - if (hostPath.containsIgnoreCase ("Wavelab 5")) return SteinbergWavelab5; - if (hostPath.containsIgnoreCase ("Wavelab 6")) return SteinbergWavelab6; - if (hostPath.containsIgnoreCase ("Wavelab 7")) return SteinbergWavelab7; - if (hostPath.containsIgnoreCase ("Wavelab 8")) return SteinbergWavelab8; - if (hostPath.containsIgnoreCase ("Nuendo")) return SteinbergNuendoGeneric; - if (hostFilename.containsIgnoreCase ("Wavelab")) return SteinbergWavelabGeneric; - if (hostFilename.containsIgnoreCase ("TestHost")) return SteinbergTestHost; - if (hostFilename.containsIgnoreCase ("rm-host")) return MuseReceptorGeneric; - if (hostFilename.startsWith ("FL")) return FruityLoops; - if (hostFilename.contains ("ilbridge.")) return FruityLoops; - if (hostPath.containsIgnoreCase ("Studio One")) return StudioOne; - if (hostPath.containsIgnoreCase ("Digital Performer")) return DigitalPerformer; - if (hostFilename.containsIgnoreCase ("VST_Scanner")) return VBVSTScanner; - if (hostPath.containsIgnoreCase ("Merging Technologies")) return MergingPyramix; - if (hostFilename.startsWithIgnoreCase ("Sam")) return MagixSamplitude; - if (hostFilename.startsWithIgnoreCase ("Sequoia")) return MagixSequoia; - if (hostFilename.containsIgnoreCase ("Renoise")) return Renoise; - if (hostFilename.containsIgnoreCase ("Resolve")) return DaVinciResolve; - if (hostPath.containsIgnoreCase ("Bitwig Studio")) return BitwigStudio; - if (hostFilename.containsIgnoreCase ("Sadie")) return SADiE; - if (hostFilename.containsIgnoreCase ("pluginval")) return pluginval; - if (hostFilename.containsIgnoreCase ("AudioPluginHost")) return JUCEPluginHost; + || hostPath.containsIgnoreCase ("Cubase 10")) return SteinbergCubase10; + if (hostFilename.containsIgnoreCase ("Cubase")) return SteinbergCubaseGeneric; + if (hostFilename.containsIgnoreCase ("VSTBridgeApp")) return SteinbergCubase5Bridged; + if (hostPath.containsIgnoreCase ("Wavelab 5")) return SteinbergWavelab5; + if (hostPath.containsIgnoreCase ("Wavelab 6")) return SteinbergWavelab6; + if (hostPath.containsIgnoreCase ("Wavelab 7")) return SteinbergWavelab7; + if (hostPath.containsIgnoreCase ("Wavelab 8")) return SteinbergWavelab8; + if (hostPath.containsIgnoreCase ("Nuendo")) return SteinbergNuendoGeneric; + if (hostFilename.containsIgnoreCase ("Wavelab")) return SteinbergWavelabGeneric; + if (hostFilename.containsIgnoreCase ("TestHost")) return SteinbergTestHost; + if (hostFilename.containsIgnoreCase ("rm-host")) return MuseReceptorGeneric; + if (hostFilename.startsWith ("FL")) return FruityLoops; + if (hostFilename.contains ("ilbridge.")) return FruityLoops; + if (hostPath.containsIgnoreCase ("Studio One")) return StudioOne; + if (hostPath.containsIgnoreCase ("Digital Performer")) return DigitalPerformer; + if (hostFilename.containsIgnoreCase ("VST_Scanner")) return VBVSTScanner; + if (hostPath.containsIgnoreCase ("Merging Technologies")) return MergingPyramix; + if (hostFilename.startsWithIgnoreCase ("Sam")) return MagixSamplitude; + if (hostFilename.startsWithIgnoreCase ("Sequoia")) return MagixSequoia; + if (hostFilename.containsIgnoreCase ("Reason")) return Reason; + if (hostFilename.containsIgnoreCase ("Renoise")) return Renoise; + if (hostFilename.containsIgnoreCase ("Resolve")) return DaVinciResolve; + if (hostPath.containsIgnoreCase ("Bitwig Studio")) return BitwigStudio; + if (hostFilename.containsIgnoreCase ("Sadie")) return SADiE; + if (hostFilename.containsIgnoreCase ("pluginval")) return pluginval; + if (hostFilename.containsIgnoreCase ("AudioPluginHost")) return JUCEPluginHost; + if (hostFilename.containsIgnoreCase ("Vienna Ensemble Pro")) return ViennaEnsemblePro; #elif JUCE_LINUX if (hostFilename.containsIgnoreCase ("Ardour")) return Ardour; diff --git a/modules/juce_audio_processors/format/juce_AudioPluginFormatManager.h b/modules/juce_audio_processors/format/juce_AudioPluginFormatManager.h index 3b7d8d31..8ae1aa6e 100644 --- a/modules/juce_audio_processors/format/juce_AudioPluginFormatManager.h +++ b/modules/juce_audio_processors/format/juce_AudioPluginFormatManager.h @@ -78,7 +78,7 @@ public: errorMessage string. If you intend to instantiate a AudioUnit v3 plug-in then you must either - use the non-blocking asynchrous version below - or call this method from a + use the non-blocking asynchronous version below - or call this method from a thread other than the message thread and without blocking the message thread. */ @@ -90,7 +90,7 @@ public: all the formats that this manager knows about. The caller must supply a callback object which will be called when - the instantantiation has completed. + the instantiation has completed. If it can't load the plugin then the callback function will be called passing a nullptr as the instance argument along with an error message. @@ -105,7 +105,7 @@ public: the callback function. If you intend to instantiate a AudioUnit v3 plug-in then you must use - this non-blocking asynchrous version - or call the synchrous method + this non-blocking asynchronous version - or call the synchronous method from an auxiliary thread. */ void createPluginInstanceAsync (const PluginDescription& description, diff --git a/modules/juce_audio_processors/format_types/juce_AudioUnitPluginFormat.mm b/modules/juce_audio_processors/format_types/juce_AudioUnitPluginFormat.mm index 33974d48..0136e58b 100644 --- a/modules/juce_audio_processors/format_types/juce_AudioUnitPluginFormat.mm +++ b/modules/juce_audio_processors/format_types/juce_AudioUnitPluginFormat.mm @@ -236,36 +236,53 @@ namespace AudioUnitFormatHelpers UseResFile (resFileId); const OSType thngType = stringToOSType ("thng"); + auto numResources = Count1Resources (thngType); - for (ResourceIndex i = 1; i <= Count1Resources (thngType); ++i) + if (numResources > 0) { - if (Handle h = Get1IndResource (thngType, i)) + for (ResourceIndex i = 1; i <= numResources; ++i) { - HLock (h); - const uint32* const types = (const uint32*) *h; - - if (types[0] == kAudioUnitType_MusicDevice - || types[0] == kAudioUnitType_MusicEffect - || types[0] == kAudioUnitType_Effect - || types[0] == kAudioUnitType_Generator - || types[0] == kAudioUnitType_Panner - || types[0] == kAudioUnitType_Mixer - || types[0] == kAudioUnitType_MIDIProcessor) + if (Handle h = Get1IndResource (thngType, i)) { - desc.componentType = types[0]; - desc.componentSubType = types[1]; - desc.componentManufacturer = types[2]; + HLock (h); + const uint32* const types = (const uint32*) *h; + + if (types[0] == kAudioUnitType_MusicDevice + || types[0] == kAudioUnitType_MusicEffect + || types[0] == kAudioUnitType_Effect + || types[0] == kAudioUnitType_Generator + || types[0] == kAudioUnitType_Panner + || types[0] == kAudioUnitType_Mixer + || types[0] == kAudioUnitType_MIDIProcessor) + { + desc.componentType = types[0]; + desc.componentSubType = types[1]; + desc.componentManufacturer = types[2]; - if (AudioComponent comp = AudioComponentFindNext (nullptr, &desc)) - getNameAndManufacturer (comp, name, manufacturer); + if (AudioComponent comp = AudioComponentFindNext (nullptr, &desc)) + getNameAndManufacturer (comp, name, manufacturer); - break; - } + break; + } - HUnlock (h); - ReleaseResource (h); + HUnlock (h); + ReleaseResource (h); + } } } + else + { + NSBundle* bundle = [[NSBundle alloc] initWithPath: (NSString*) fileOrIdentifier.toCFString()]; + + NSArray* audioComponents = [bundle objectForInfoDictionaryKey: @"AudioComponents"]; + NSDictionary* dict = audioComponents[0]; + + desc.componentManufacturer = stringToOSType (nsStringToJuce ((NSString*) [dict valueForKey: @"manufacturer"])); + desc.componentType = stringToOSType (nsStringToJuce ((NSString*) [dict valueForKey: @"type"])); + desc.componentSubType = stringToOSType (nsStringToJuce ((NSString*) [dict valueForKey: @"subtype"])); + + [bundle release]; + } CFBundleCloseBundleResourceMap (bundleRef, resFileId); CFRelease (bundleRef); @@ -781,19 +798,19 @@ public: // try to convert the layout into a tag actualTag = CoreAudioLayouts::toCoreAudio (CoreAudioLayouts::fromCoreAudio (layout)); - } - if (actualTag != requestedTag) - { - zerostruct (layout); - layout.mChannelLayoutTag = requestedTag; + if (actualTag != requestedTag) + { + zerostruct (layout); + layout.mChannelLayoutTag = requestedTag; - err = AudioUnitSetProperty (audioUnit, kAudioUnitProperty_AudioChannelLayout, scope, static_cast (i), &layout, minDataSize); + err = AudioUnitSetProperty (audioUnit, kAudioUnitProperty_AudioChannelLayout, scope, static_cast (i), &layout, minDataSize); - // only bail out if the plug-in claims to support layouts - // See AudioUnit headers on kAudioUnitProperty_AudioChannelLayout - if (err != noErr && supportsLayouts && isInitialized) - return false; + // only bail out if the plug-in claims to support layouts + // See AudioUnit headers on kAudioUnitProperty_AudioChannelLayout + if (err != noErr && supportsLayouts && isInitialized) + return false; + } } } } @@ -1239,7 +1256,18 @@ public: { AUPreset current; current.presetNumber = newIndex; - current.presetName = CFSTR(""); + + CFArrayRef presets; + UInt32 sz = sizeof (CFArrayRef); + + if (AudioUnitGetProperty (audioUnit, kAudioUnitProperty_FactoryPresets, + kAudioUnitScope_Global, 0, &presets, &sz) == noErr) + { + if (auto* p = (const AUPreset*) CFArrayGetValueAtIndex (presets, newIndex)) + current.presetName = p->presetName; + + CFRelease (presets); + } AudioUnitSetProperty (audioUnit, kAudioUnitProperty_PresentPreset, kAudioUnitScope_Global, 0, ¤t, sizeof (AUPreset)); @@ -1253,12 +1281,25 @@ public: CFArrayRef presets; UInt32 sz = sizeof (CFArrayRef); - if (AudioUnitGetProperty (audioUnit, kAudioUnitProperty_FactoryPresets, - kAudioUnitScope_Global, 0, &presets, &sz) == noErr) + if (index == -1) + { + AUPreset current; + current.presetNumber = -1; + current.presetName = CFSTR(""); + + UInt32 prstsz = sizeof (AUPreset); + + AudioUnitGetProperty (audioUnit, kAudioUnitProperty_PresentPreset, + kAudioUnitScope_Global, 0, ¤t, &prstsz); + + s = String::fromCFString (current.presetName); + } + else if (AudioUnitGetProperty (audioUnit, kAudioUnitProperty_FactoryPresets, + kAudioUnitScope_Global, 0, &presets, &sz) == noErr) { for (CFIndex i = 0; i < CFArrayGetCount (presets); ++i) { - if (const AUPreset* p = (const AUPreset*) CFArrayGetValueAtIndex (presets, i)) + if (auto* p = (const AUPreset*) CFArrayGetValueAtIndex (presets, i)) { if (p->presetNumber == index) { @@ -1791,14 +1832,23 @@ private: default: if (event.mArgument.mProperty.mPropertyID == kAudioUnitProperty_ParameterList) + { updateHostDisplay(); + } else if (event.mArgument.mProperty.mPropertyID == kAudioUnitProperty_PresentPreset) + { sendAllParametersChangedEvents(); + updateHostDisplay(); + } else if (event.mArgument.mProperty.mPropertyID == kAudioUnitProperty_Latency) + { updateLatency(); + } else if (event.mArgument.mProperty.mPropertyID == kAudioUnitProperty_BypassEffect) + { if (bypassParam != nullptr) bypassParam->setValueNotifyingHost (bypassParam->getValue()); + } break; } diff --git a/modules/juce_audio_processors/format_types/juce_VST3Common.h b/modules/juce_audio_processors/format_types/juce_VST3Common.h index dbbc8e16..dc40caf6 100644 --- a/modules/juce_audio_processors/format_types/juce_VST3Common.h +++ b/modules/juce_audio_processors/format_types/juce_VST3Common.h @@ -536,7 +536,7 @@ public: } } - Steinberg::Vst::Event e = { 0 }; + Steinberg::Vst::Event e{}; if (msg.isNoteOn()) { diff --git a/modules/juce_audio_processors/format_types/juce_VST3Headers.h b/modules/juce_audio_processors/format_types/juce_VST3Headers.h index ccdfa19a..f8b1351d 100644 --- a/modules/juce_audio_processors/format_types/juce_VST3Headers.h +++ b/modules/juce_audio_processors/format_types/juce_VST3Headers.h @@ -65,6 +65,12 @@ #if __has_warning("-Wcast-align") #pragma clang diagnostic ignored "-Wcast-align" #endif + #if __has_warning("-Wignored-qualifiers") + #pragma clang diagnostic ignored "-Wignored-qualifiers" + #endif + #if __has_warning("-Wmissing-field-initializers") + #pragma clang diagnostic ignored "-Wmissing-field-initializers" + #endif #endif #undef DEVELOPMENT diff --git a/modules/juce_audio_processors/format_types/juce_VST3PluginFormat.cpp b/modules/juce_audio_processors/format_types/juce_VST3PluginFormat.cpp index 14810fb5..4e290c53 100644 --- a/modules/juce_audio_processors/format_types/juce_VST3PluginFormat.cpp +++ b/modules/juce_audio_processors/format_types/juce_VST3PluginFormat.cpp @@ -774,7 +774,8 @@ struct DescriptionFactory } } - result = performOnDescription (desc); + if (desc.uid != 0) + result = performOnDescription (desc); if (result.failed()) break; @@ -1593,9 +1594,11 @@ public: struct VST3Parameter final : public Parameter { VST3Parameter (VST3PluginInstance& parent, + int vstParameterIndex, Steinberg::Vst::ParamID parameterID, bool parameterIsAutomatable) : pluginInstance (parent), + vstParamIndex (vstParameterIndex), paramID (parameterID), automatable (parameterIsAutomatable) { @@ -1653,19 +1656,24 @@ public: return Parameter::getValueForText (text); } + Vst::ParameterInfo getParameterInfo() const + { + return pluginInstance.getParameterInfoForIndex (vstParamIndex); + } + float getDefaultValue() const override { - return (float) pluginInstance.getParameterInfoForIndex (getParameterIndex()).defaultNormalizedValue; + return (float) getParameterInfo().defaultNormalizedValue; } String getName (int /*maximumStringLength*/) const override { - return toString (pluginInstance.getParameterInfoForIndex (getParameterIndex()).title); + return toString (getParameterInfo().title); } String getLabel() const override { - return toString (pluginInstance.getParameterInfoForIndex (getParameterIndex()).units); + return toString (getParameterInfo().units); } bool isAutomatable() const override @@ -1680,7 +1688,7 @@ public: int getNumSteps() const override { - auto stepCount = pluginInstance.getParameterInfoForIndex (getParameterIndex()).stepCount; + auto stepCount = getParameterInfo().stepCount; return stepCount == 0 ? AudioProcessor::getDefaultNumParameterSteps() : stepCount + 1; } @@ -1691,6 +1699,7 @@ public: } VST3PluginInstance& pluginInstance; + const int vstParamIndex; const Steinberg::Vst::ParamID paramID; const bool automatable; }; @@ -1699,7 +1708,7 @@ public: VST3PluginInstance (VST3ComponentHolder* componentHolder) : AudioPluginInstance (getBusProperties (componentHolder->component)), holder (componentHolder), - inputParameterChanges (new ParamValueQueueList()), + inputParameterChanges (new ParamValueQueueList()), outputParameterChanges (new ParamValueQueueList()), midiInputs (new MidiEventList()), midiOutputs (new MidiEventList()) @@ -2337,23 +2346,37 @@ public: JUCE_DECLARE_VST3_COM_REF_METHODS JUCE_DECLARE_VST3_COM_QUERY_METHODS - Steinberg::int32 PLUGIN_API getParameterCount() override { return numQueuesUsed; } - Vst::IParamValueQueue* PLUGIN_API getParameterData (Steinberg::int32 index) override { return isPositiveAndBelow (static_cast (index), numQueuesUsed) ? queues[(int) index] : nullptr; } + Steinberg::int32 PLUGIN_API getParameterCount() override + { + const ScopedLock sl (queuesLock); + return numQueuesUsed; + } + + Vst::IParamValueQueue* PLUGIN_API getParameterData (Steinberg::int32 index) override + { + const ScopedLock sl (queuesLock); + return isPositiveAndBelow (static_cast (index), numQueuesUsed) ? queues[(int) index] : nullptr; + } Vst::IParamValueQueue* PLUGIN_API addParameterData (const Vst::ParamID& id, Steinberg::int32& index) override { + const ScopedLock sl (queuesLock); + for (int i = numQueuesUsed; --i >= 0;) { - if (queues.getUnchecked (i)->getParameterId() == id) + if (auto* q = queues.getUnchecked (i)) { - index = (Steinberg::int32) i; - return queues.getUnchecked (i); + if (q->getParameterId() == id) + { + index = (Steinberg::int32) i; + return q; + } } } index = numQueuesUsed++; - ParamValueQueue* valueQueue = (index < queues.size() ? queues[index] - : queues.add (new ParamValueQueue())); + auto* valueQueue = (index < queues.size() ? queues[index] + : queues.add (new ParamValueQueue())); valueQueue->clear(); valueQueue->setParamID (id); @@ -2363,6 +2386,7 @@ public: void clearAllQueues() noexcept { + const ScopedLock sl (queuesLock); numQueuesUsed = 0; } @@ -2387,18 +2411,20 @@ public: Steinberg::int32& sampleOffset, Steinberg::Vst::ParamValue& value) override { - const ScopedLock sl (pointLock); + const ScopedLock sl (points.getLock()); if (isPositiveAndBelow ((int) index, points.size())) { - ParamPoint e (points.getUnchecked ((int) index)); + auto e = points.getUnchecked ((int) index); sampleOffset = e.sampleOffset; value = e.value; + return kResultTrue; } sampleOffset = -1; value = 0.0; + return kResultFalse; } @@ -2406,19 +2432,12 @@ public: Steinberg::Vst::ParamValue value, Steinberg::int32& index) override { - ParamPoint p = { sampleOffset, value }; - - const ScopedLock sl (pointLock); index = (Steinberg::int32) points.size(); - points.add (p); + points.add ({ sampleOffset, value }); return kResultTrue; } - void clear() noexcept - { - const ScopedLock sl (pointLock); - points.clearQuick(); - } + void clear() noexcept { points.clearQuick(); } private: struct ParamPoint @@ -2429,15 +2448,16 @@ public: Atomic refCount; Vst::ParamID paramID = static_cast (-1); - Array points; - CriticalSection pointLock; + Array points; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ParamValueQueue) }; Atomic refCount; + OwnedArray queues; int numQueuesUsed = 0; + CriticalSection queuesLock; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ParamValueQueueList) }; @@ -2549,7 +2569,7 @@ private: for (int i = 1; i < numUnits; ++i) { - Vst::UnitInfo ui = { 0 }; + Vst::UnitInfo ui{}; unitInfo->getUnitInfo (i, ui); infoMap[ui.id] = std::move (ui); } @@ -2559,6 +2579,7 @@ private: { auto paramInfo = getParameterInfoForIndex (i); auto* param = new VST3Parameter (*this, + i, paramInfo.id, (paramInfo.flags & Vst::ParameterInfo::kCanAutomate) != 0); @@ -2566,7 +2587,6 @@ private: bypassParam = param; std::function findOrCreateGroup; - findOrCreateGroup = [&groupMap, &infoMap, &findOrCreateGroup](Vst::UnitID groupID) { auto existingGroup = groupMap.find (groupID); @@ -2765,7 +2785,7 @@ private: Vst::ParameterInfo getParameterInfoForIndex (int index) const { - Vst::ParameterInfo paramInfo = { 0 }; + Vst::ParameterInfo paramInfo{}; if (processor != nullptr) editController->getParameterInfo (index, paramInfo); @@ -2775,7 +2795,7 @@ private: Vst::ProgramListInfo getProgramListInfo (int index) const { - Vst::ProgramListInfo paramInfo = { 0 }; + Vst::ProgramListInfo paramInfo{}; if (unitInfo != nullptr) unitInfo->getProgramListInfo (index, paramInfo); @@ -2791,7 +2811,7 @@ private: return; Vst::UnitID programUnitID; - Vst::ParameterInfo paramInfo = { 0 }; + Vst::ParameterInfo paramInfo{}; { int idx, num = editController->getParameterCount(); @@ -2810,7 +2830,7 @@ private: if (unitInfo != nullptr) { - Vst::UnitInfo uInfo = { 0 }; + Vst::UnitInfo uInfo{}; const int unitCount = unitInfo->getUnitCount(); for (int idx = 0; idx < unitCount; ++idx) @@ -2822,7 +2842,7 @@ private: for (int j = 0; j < programListCount; ++j) { - Vst::ProgramListInfo programListInfo = { 0 }; + Vst::ProgramListInfo programListInfo{}; if (unitInfo->getProgramListInfo (j, programListInfo) == kResultOk && programListInfo.id == uInfo.programListId) @@ -3014,7 +3034,19 @@ tresult VST3HostContext::ContextMenu::popup (Steinberg::UCoord x, Steinberg::UCo PopupMenu::Options options; if (auto* ed = owner.getActiveEditor()) + { + #if JUCE_WINDOWS && JUCE_WIN_PER_MONITOR_DPI_AWARE + if (auto* peer = ed->getPeer()) + { + auto scale = peer->getPlatformScaleFactor(); + + x = roundToInt (x / scale); + y = roundToInt (y / scale); + } + #endif + options = options.withTargetScreenArea (ed->getScreenBounds().translated ((int) x, (int) y).withSize (1, 1)); + } #if JUCE_MODAL_LOOPS_PERMITTED // Unfortunately, Steinberg's docs explicitly say this should be modal.. diff --git a/modules/juce_audio_processors/format_types/juce_VSTPluginFormat.cpp b/modules/juce_audio_processors/format_types/juce_VSTPluginFormat.cpp index 85dfb785..bdc935fc 100644 --- a/modules/juce_audio_processors/format_types/juce_VSTPluginFormat.cpp +++ b/modules/juce_audio_processors/format_types/juce_VSTPluginFormat.cpp @@ -1213,7 +1213,7 @@ struct VSTPluginInstance : public AudioPluginInstance, desc.version = getVersion(); desc.numInputChannels = getTotalNumInputChannels(); desc.numOutputChannels = getTotalNumOutputChannels(); - desc.isInstrument = (vstEffect != nullptr && (vstEffect->flags & Vst2::effFlagsIsSynth) != 0); + desc.isInstrument = isSynthPlugin(); } bool initialiseEffect (double initialSampleRate, int initialBlockSize) @@ -1269,7 +1269,7 @@ struct VSTPluginInstance : public AudioPluginInstance, if (getVstCategory() != Vst2::kPlugCategShell) // (workaround for Waves 5 plugins which crash during this call) updateStoredProgramNames(); - wantsMidiMessages = pluginCanDo ("receiveVstMidiEvent") > 0; + wantsMidiMessages = pluginCanDo ("receiveVstMidiEvent") > 0 || isSynthPlugin(); #if JUCE_MAC && JUCE_SUPPORT_CARBON usesCocoaNSView = ((unsigned int) pluginCanDo ("hasCockosViewAsConfig") & 0xffff0000ul) == 0xbeef0000ul; @@ -1338,7 +1338,9 @@ struct VSTPluginInstance : public AudioPluginInstance, Vst2::VstPlugCategory getVstCategory() const noexcept { return (Vst2::VstPlugCategory) dispatch (Vst2::effGetPlugCategory, 0, 0, nullptr, 0); } - int pluginCanDo (const char* text) const { return (int) dispatch (Vst2::effCanDo, 0, 0, (void*) text, 0); } + bool isSynthPlugin() const { return (vstEffect != nullptr && (vstEffect->flags & Vst2::effFlagsIsSynth) != 0); } + + int pluginCanDo (const char* text) const { return (int) dispatch (Vst2::effCanDo, 0, 0, (void*) text, 0); } //============================================================================== void prepareToPlay (double rate, int samplesPerBlockExpected) override @@ -1369,7 +1371,7 @@ struct VSTPluginInstance : public AudioPluginInstance, if (initialised) { - wantsMidiMessages = wantsMidiMessages || (pluginCanDo ("receiveVstMidiEvent") > 0); + wantsMidiMessages = wantsMidiMessages || (pluginCanDo ("receiveVstMidiEvent") > 0) || isSynthPlugin(); if (wantsMidiMessages) midiEventsToSend.ensureSize (256); @@ -2050,7 +2052,8 @@ private: //============================================================================== String name; CriticalSection lock; - bool wantsMidiMessages = false, initialised = false, isPowerOn = false; + std::atomic wantsMidiMessages { false }; + bool initialised = false, isPowerOn = false; bool lastProcessBlockCallWasBypass = false, vstSupportsBypass = false; mutable StringArray programNames; AudioBuffer outOfPlaceBuffer; @@ -2319,7 +2322,7 @@ private: // Workaround: unfortunately old JUCE VST-2 plug-ins had a bug and would crash if // you try to get the speaker arrangement when there are no input channels present. // Hopefully, one day (when there are no more old JUCE plug-ins around), we can - // commment out the next two lines. + // comment out the next two lines. if (effect->numInputs == 0) return false; @@ -2924,7 +2927,11 @@ public: if (auto* peer = getTopLevelComponent()->getPeer()) setScaleFactorAndDispatchMessage (peer->getPlatformScaleFactor()); + #if JUCE_LINUX + MessageManager::callAsync ([this] { componentMovedOrResized (true, true); }); + #else componentMovedOrResized (true, true); + #endif } using ComponentMovementWatcher::componentVisibilityChanged; diff --git a/modules/juce_audio_processors/juce_audio_processors.h b/modules/juce_audio_processors/juce_audio_processors.h index 62b0f498..f2f4c73d 100644 --- a/modules/juce_audio_processors/juce_audio_processors.h +++ b/modules/juce_audio_processors/juce_audio_processors.h @@ -24,6 +24,7 @@ ============================================================================== */ + /******************************************************************************* The block below describes the properties of this module, and is read by the Projucer to automatically generate project code that uses it. @@ -33,17 +34,17 @@ BEGIN_JUCE_MODULE_DECLARATION - ID: juce_audio_processors - vendor: juce - version: 5.4.5 - name: JUCE audio processor classes - description: Classes for loading and playing VST, AU, LADSPA, or internally-generated audio processors. - website: http://www.juce.com/juce - license: GPL/Commercial - - dependencies: juce_gui_extra, juce_audio_basics - OSXFrameworks: CoreAudio CoreMIDI AudioToolbox - iOSFrameworks: AudioToolbox + ID: juce_audio_processors + vendor: juce + version: 5.4.6 + name: JUCE audio processor classes + description: Classes for loading and playing VST, AU, LADSPA, or internally-generated audio processors. + website: http://www.juce.com/juce + license: GPL/Commercial + + dependencies: juce_gui_extra, juce_audio_basics + OSXFrameworks: CoreAudio CoreMIDI AudioToolbox + iOSFrameworks: AudioToolbox END_JUCE_MODULE_DECLARATION diff --git a/modules/juce_audio_processors/processors/juce_AudioProcessor.cpp b/modules/juce_audio_processors/processors/juce_AudioProcessor.cpp index 7e62e7a2..bd40623c 100644 --- a/modules/juce_audio_processors/processors/juce_AudioProcessor.cpp +++ b/modules/juce_audio_processors/processors/juce_AudioProcessor.cpp @@ -52,8 +52,12 @@ AudioProcessor::AudioProcessor (const BusesProperties& ioConfig) AudioProcessor::~AudioProcessor() { - // ooh, nasty - the editor should have been deleted before its AudioProcessor. - jassert (activeEditor == nullptr); + { + const ScopedLock sl (activeEditorLock); + + // ooh, nasty - the editor should have been deleted before its AudioProcessor. + jassert (activeEditor == nullptr); + } #if JUCE_DEBUG && ! JUCE_DISABLE_AUDIOPROCESSOR_BEGIN_END_GESTURE_CHECKING // This will fail if you've called beginParameterChangeGesture() for one @@ -424,41 +428,18 @@ void AudioProcessor::updateHostDisplay() l->audioProcessorChanged (this); } -#if JUCE_DEBUG -void AudioProcessor::checkDuplicateParamIDs() +void AudioProcessor::checkForDuplicateParamID (AudioProcessorParameter* param) { - duplicateParamIDCheck.reset(); - - StringArray usedIDs; - usedIDs.ensureStorageAllocated (flatParameterList.size()); - - for (auto& p : flatParameterList) - if (auto* withID = dynamic_cast (p)) - usedIDs.add (withID->paramID); - - usedIDs.sort (false); - - // This assertion checks whether you attempted to add two or more parameters with the same ID - for (int i = 1; i < usedIDs.size(); ++i) - jassert (usedIDs[i - 1] != usedIDs[i]); -} + ignoreUnused (param); -struct AudioProcessor::DuplicateParamIDCheck : private AsyncUpdater -{ - DuplicateParamIDCheck (AudioProcessor& p) : owner (p) { triggerAsyncUpdate(); } - ~DuplicateParamIDCheck() override { cancelPendingUpdate(); } - - void handleAsyncUpdate() override { owner.checkDuplicateParamIDs(); } - - AudioProcessor& owner; -}; -#endif - -void AudioProcessor::triggerDuplicateParamIDCheck() -{ #if JUCE_DEBUG - if (MessageManager::getInstanceWithoutCreating() != nullptr) - duplicateParamIDCheck = std::make_unique (*this); + if (auto* withID = dynamic_cast (param)) + { + auto insertResult = paramIDs.insert (withID->paramID); + + // If you hit this assertion then the parameter ID is not unique + jassert (insertResult.second); + } #endif } @@ -474,7 +455,7 @@ void AudioProcessor::addParameter (AudioProcessorParameter* param) param->parameterIndex = flatParameterList.size(); flatParameterList.add (param); - triggerDuplicateParamIDCheck(); + checkForDuplicateParamID (param); } void AudioProcessor::addParameterGroup (std::unique_ptr group) @@ -489,14 +470,19 @@ void AudioProcessor::addParameterGroup (std::unique_ptrprocessor = this; p->parameterIndex = i; + + checkForDuplicateParamID (p); } parameterTree.addChild (std::move (group)); - triggerDuplicateParamIDCheck(); } void AudioProcessor::setParameterTree (AudioProcessorParameterGroup&& newTree) { + #if JUCE_DEBUG + paramIDs.clear(); + #endif + parameterTree = std::move (newTree); flatParameterList = parameterTree.getParameters (true); @@ -505,9 +491,9 @@ void AudioProcessor::setParameterTree (AudioProcessorParameterGroup&& newTree) auto p = flatParameterList.getUnchecked (i); p->processor = this; p->parameterIndex = i; - } - triggerDuplicateParamIDCheck(); + checkForDuplicateParamID (p); + } } void AudioProcessor::refreshParameterList() {} @@ -821,14 +807,22 @@ void AudioProcessor::audioIOChanged (bool busNumberChanged, bool channelNumChang //============================================================================== void AudioProcessor::editorBeingDeleted (AudioProcessorEditor* const editor) noexcept { - const ScopedLock sl (callbackLock); + const ScopedLock sl (activeEditorLock); if (activeEditor == editor) activeEditor = nullptr; } +AudioProcessorEditor* AudioProcessor::getActiveEditor() const noexcept +{ + const ScopedLock sl (activeEditorLock); + return activeEditor; +} + AudioProcessorEditor* AudioProcessor::createEditorIfNeeded() { + const ScopedLock sl (activeEditorLock); + if (activeEditor != nullptr) return activeEditor; @@ -838,8 +832,6 @@ AudioProcessorEditor* AudioProcessor::createEditorIfNeeded() { // you must give your editor comp a size before returning it.. jassert (ed->getWidth() > 0 && ed->getHeight() > 0); - - const ScopedLock sl (callbackLock); activeEditor = ed; } diff --git a/modules/juce_audio_processors/processors/juce_AudioProcessor.h b/modules/juce_audio_processors/processors/juce_AudioProcessor.h index 04a11a92..836b09c7 100644 --- a/modules/juce_audio_processors/processors/juce_AudioProcessor.h +++ b/modules/juce_audio_processors/processors/juce_AudioProcessor.h @@ -51,7 +51,7 @@ protected: //============================================================================== /** Constructor. - This constructor will create a main input and output bus which are diabled + This constructor will create a main input and output bus which are disabled by default. If you need more fine-grained control then use the other constructors. */ AudioProcessor(); @@ -400,7 +400,7 @@ public: /** Return the number of channels of the current bus. */ inline int getNumberOfChannels() const noexcept { return cachedChannelCount; } - /** Set the number of channles of this bus. This will return false if the AudioProcessor + /** Set the number of channels of this bus. This will return false if the AudioProcessor does not support this layout. */ bool setNumberOfChannels (int channels); @@ -627,7 +627,7 @@ public: */ int getChannelIndexInProcessBlockBuffer (bool isInput, int busIndex, int channelIndex) const noexcept; - /** Returns the offset in a bus's buffer from an absolute channel indes. + /** Returns the offset in a bus's buffer from an absolute channel index. This method returns the offset in a bus's buffer given an absolute channel index. It also provides the bus index. For example, this method would return one @@ -771,7 +771,7 @@ public: /** Returns the next best layout which is contained in a channel layout map. - You can use this mehtod to help you implement getNextBestLayout. For example: + You can use this method to help you implement getNextBestLayout. For example: @code BusesLayout getNextBestLayout (const BusesLayout& layouts) override @@ -900,7 +900,7 @@ public: If this method returns a nullptr then you can still control the bypass by calling processBlockBypassed instead of processBlock. On the other hand, if this method returns a non-null value, you should never call - processBlockBypassed but use the returned parameter to conrol the bypass + processBlockBypassed but use the returned parameter to control the bypass state instead. A plug-in can override this function to return a parameter which control's your @@ -964,10 +964,13 @@ public: virtual bool hasEditor() const = 0; //============================================================================== - /** Returns the active editor, if there is one. - Bear in mind this can return nullptr, even if an editor has previously been opened. + /** Returns the active editor, if there is one. Bear in mind this can return nullptr + even if an editor has previously been opened. + + Note that you should only call this method from the message thread as the active + editor may be deleted by the message thread, causing a dangling pointer. */ - AudioProcessorEditor* getActiveEditor() const noexcept { return activeEditor; } + AudioProcessorEditor* getActiveEditor() const noexcept; /** Returns the active editor, or if there isn't one, it will create one. This may call createEditor() internally to create the component. @@ -1011,14 +1014,21 @@ public: /** Returns the group of parameters managed by this AudioProcessor. */ const AudioProcessorParameterGroup& getParameterTree() const; - /** Sets the group of parameters managed by this AudioProcessor. */ + /** Sets the group of parameters managed by this AudioProcessor. + + Replacing the tree after your AudioProcessor has been constructed will + crash many hosts, so don't do it! You may, however, change parameter and + group names by iterating the tree returned by getParameterTree(). + Afterwards, call updateHostDisplay() to inform the host of the changes. + Not all hosts support dynamic changes to parameters and group names. + */ void setParameterTree (AudioProcessorParameterGroup&& newTree); /** A processor should implement this method so that the host can ask it to rebuild its parameter tree. - If a plugin never changes its parameters, it's enough to create its - parameters in its constructor and do nothing in this method, but some - may want to + + For most plug-ins it's enough to simply add your parameters in the + constructor and leave this unimplemented. */ virtual void refreshParameterList(); @@ -1221,7 +1231,7 @@ public: AudioProcessor about which track the AudioProcessor is loaded on. This method may only be called on the message thread. - If you are implemeting an AudioProcessor then you can override this callback + If you are implementing an AudioProcessor then you can override this callback to do something useful with the track properties such as changing the colour of your AudioProcessor's editor. It's entirely up to the host when and how often this callback will be called. @@ -1362,7 +1372,7 @@ protected: //============================================================================== /** @internal */ - AudioPlayHead* playHead = nullptr; + std::atomic playHead { nullptr }; /** @internal */ void sendParamChangeMessageToListeners (int parameterIndex, float newValue); @@ -1458,7 +1468,7 @@ private: int blockSize = 0, latencySamples = 0; bool suspended = false, nonRealtime = false; ProcessingPrecision processingPrecision = singlePrecision; - CriticalSection callbackLock, listenerLock; + CriticalSection callbackLock, listenerLock, activeEditorLock; friend class Bus; mutable OwnedArray inputBuses, outputBuses; @@ -1477,17 +1487,15 @@ private: #endif bool textRecursionCheck = false; - - struct DuplicateParamIDCheck; - std::unique_ptr duplicateParamIDCheck; - void checkDuplicateParamIDs(); + std::unordered_set paramIDs; #endif + void checkForDuplicateParamID (AudioProcessorParameter*); + AudioProcessorListener* getListenerLocked (int) const noexcept; void updateSpeakerFormatStrings(); void audioIOChanged (bool busNumberChanged, bool channelNumChanged); void getNextBestLayout (const BusesLayout&, BusesLayout&) const; - void triggerDuplicateParamIDCheck(); template void processBypassed (AudioBuffer&, MidiBuffer&); diff --git a/modules/juce_audio_processors/processors/juce_AudioProcessorEditor.cpp b/modules/juce_audio_processors/processors/juce_AudioProcessorEditor.cpp index 8e44bb29..0c660ae6 100644 --- a/modules/juce_audio_processors/processors/juce_AudioProcessorEditor.cpp +++ b/modules/juce_audio_processors/processors/juce_AudioProcessorEditor.cpp @@ -103,15 +103,9 @@ void AudioProcessorEditor::setResizable (const bool shouldBeResizable, const boo if (shouldHaveCornerResizer != (resizableCorner != nullptr)) { if (shouldHaveCornerResizer) - { - resizableCorner.reset (new ResizableCornerComponent (this, constrainer)); - Component::addChildComponent (resizableCorner.get()); - resizableCorner->setAlwaysOnTop (true); - } + attachResizableCornerComponent(); else - { resizableCorner.reset(); - } } } @@ -146,6 +140,9 @@ void AudioProcessorEditor::setConstrainer (ComponentBoundsConstrainer* newConstr || newConstrainer->getMinimumHeight() != newConstrainer->getMaximumHeight()); attachConstrainer (newConstrainer); + + if (resizableCorner != nullptr) + attachResizableCornerComponent(); } } @@ -158,6 +155,14 @@ void AudioProcessorEditor::attachConstrainer (ComponentBoundsConstrainer* newCon } } +void AudioProcessorEditor::attachResizableCornerComponent() +{ + resizableCorner.reset (new ResizableCornerComponent (this, constrainer)); + Component::addChildComponent (resizableCorner.get()); + resizableCorner->setAlwaysOnTop (true); + editorResized (true); +} + void AudioProcessorEditor::setBoundsConstrained (Rectangle newBounds) { if (constrainer != nullptr) diff --git a/modules/juce_audio_processors/processors/juce_AudioProcessorEditor.h b/modules/juce_audio_processors/processors/juce_AudioProcessorEditor.h index d7f9282f..623390ff 100644 --- a/modules/juce_audio_processors/processors/juce_AudioProcessorEditor.h +++ b/modules/juce_audio_processors/processors/juce_AudioProcessorEditor.h @@ -200,6 +200,7 @@ private: void editorResized (bool wasResized); void updatePeer(); void attachConstrainer (ComponentBoundsConstrainer*); + void attachResizableCornerComponent(); //============================================================================== std::unique_ptr resizeListener; diff --git a/modules/juce_audio_processors/processors/juce_AudioProcessorGraph.cpp b/modules/juce_audio_processors/processors/juce_AudioProcessorGraph.cpp index 123b2e39..1a016a9c 100644 --- a/modules/juce_audio_processors/processors/juce_AudioProcessorGraph.cpp +++ b/modules/juce_audio_processors/processors/juce_AudioProcessorGraph.cpp @@ -275,18 +275,18 @@ private: tempBufferDouble.makeCopyOf (buffer, true); if (node->isBypassed()) - processor.processBlockBypassed (tempBufferDouble, midiMessages); + node->processBlockBypassed (tempBufferDouble, midiMessages); else - processor.processBlock (tempBufferDouble, midiMessages); + node->processBlock (tempBufferDouble, midiMessages); buffer.makeCopyOf (tempBufferDouble, true); } else { if (node->isBypassed()) - processor.processBlockBypassed (buffer, midiMessages); + node->processBlockBypassed (buffer, midiMessages); else - processor.processBlock (buffer, midiMessages); + node->processBlock (buffer, midiMessages); } } @@ -295,18 +295,18 @@ private: if (processor.isUsingDoublePrecision()) { if (node->isBypassed()) - processor.processBlockBypassed (buffer, midiMessages); + node->processBlockBypassed (buffer, midiMessages); else - processor.processBlock (buffer, midiMessages); + node->processBlock (buffer, midiMessages); } else { tempBufferFloat.makeCopyOf (buffer, true); if (node->isBypassed()) - processor.processBlockBypassed (tempBufferFloat, midiMessages); + node->processBlockBypassed (tempBufferFloat, midiMessages); else - processor.processBlock (tempBufferFloat, midiMessages); + node->processBlock (tempBufferFloat, midiMessages); buffer.makeCopyOf (tempBufferFloat, true); } @@ -806,9 +806,10 @@ AudioProcessorGraph::Node::Node (NodeID n, std::unique_ptr p) no void AudioProcessorGraph::Node::prepare (double newSampleRate, int newBlockSize, AudioProcessorGraph* graph, ProcessingPrecision precision) { + const ScopedLock lock (processorLock); + if (! isPrepared) { - isPrepared = true; setParentGraph (graph); // try to align the precision of the processor and the graph @@ -817,11 +818,17 @@ void AudioProcessorGraph::Node::prepare (double newSampleRate, int newBlockSize, processor->setRateAndBufferSizeDetails (newSampleRate, newBlockSize); processor->prepareToPlay (newSampleRate, newBlockSize); + + // This may be checked from other threads that haven't taken the processorLock, + // so we need to leave it until the processor has been completely prepared + isPrepared = true; } } void AudioProcessorGraph::Node::unprepare() { + const ScopedLock lock (processorLock); + if (isPrepared) { isPrepared = false; @@ -831,6 +838,8 @@ void AudioProcessorGraph::Node::unprepare() void AudioProcessorGraph::Node::setParentGraph (AudioProcessorGraph* const graph) const { + const ScopedLock lock (processorLock); + if (auto* ioProc = dynamic_cast (processor.get())) ioProc->setParentGraph (graph); } @@ -876,6 +885,7 @@ AudioProcessorGraph::AudioProcessorGraph() AudioProcessorGraph::~AudioProcessorGraph() { + cancelPendingUpdate(); clearRenderingSequence(); clear(); } @@ -890,7 +900,7 @@ void AudioProcessorGraph::topologyChanged() { sendChangeMessage(); - if (isPrepared.get() != 0) + if (isPrepared) triggerAsyncUpdate(); } @@ -940,7 +950,12 @@ AudioProcessorGraph::Node::Ptr AudioProcessorGraph::addNode (std::unique_ptrsetPlayHead (getPlayHead()); Node::Ptr n (new Node (nodeID, std::move (newProcessor))); - nodes.add (n.get()); + + { + const ScopedLock sl (getCallbackLock()); + nodes.add (n.get()); + } + n->setParentGraph (this); topologyChanged(); return n; @@ -948,6 +963,8 @@ AudioProcessorGraph::Node::Ptr AudioProcessorGraph::addNode (std::unique_ptr= 0;) { if (nodes.getUnchecked(i)->nodeID == nodeId) @@ -1203,50 +1220,46 @@ bool AudioProcessorGraph::anyNodesNeedPreparing() const noexcept void AudioProcessorGraph::buildRenderingSequence() { - std::unique_ptr newSequenceF (new RenderSequenceFloat()); - std::unique_ptr newSequenceD (new RenderSequenceDouble()); + auto newSequenceF = std::make_unique(); + auto newSequenceD = std::make_unique(); - { - MessageManagerLock mml; + RenderSequenceBuilder builderF (*this, *newSequenceF); + RenderSequenceBuilder builderD (*this, *newSequenceD); - RenderSequenceBuilder builderF (*this, *newSequenceF); - RenderSequenceBuilder builderD (*this, *newSequenceD); - } + const ScopedLock sl (getCallbackLock()); - { - const ScopedLock sl (getCallbackLock()); - newSequenceF->prepareBuffers (getBlockSize()); - newSequenceD->prepareBuffers (getBlockSize()); - } + const auto currentBlockSize = getBlockSize(); + newSequenceF->prepareBuffers (currentBlockSize); + newSequenceD->prepareBuffers (currentBlockSize); if (anyNodesNeedPreparing()) { - { - const ScopedLock sl (getCallbackLock()); - renderSequenceFloat.reset(); - renderSequenceDouble.reset(); - } + renderSequenceFloat.reset(); + renderSequenceDouble.reset(); for (auto* node : nodes) - node->prepare (getSampleRate(), getBlockSize(), this, getProcessingPrecision()); + node->prepare (getSampleRate(), currentBlockSize, this, getProcessingPrecision()); } - const ScopedLock sl (getCallbackLock()); + isPrepared = 1; - std::swap (renderSequenceFloat, newSequenceF); + std::swap (renderSequenceFloat, newSequenceF); std::swap (renderSequenceDouble, newSequenceD); } void AudioProcessorGraph::handleAsyncUpdate() { buildRenderingSequence(); - isPrepared = 1; } //============================================================================== void AudioProcessorGraph::prepareToPlay (double sampleRate, int estimatedSamplesPerBlock) { - setRateAndBufferSizeDetails (sampleRate, estimatedSamplesPerBlock); + { + const ScopedLock sl (getCallbackLock()); + setRateAndBufferSizeDetails (sampleRate, estimatedSamplesPerBlock); + } + clearRenderingSequence(); if (MessageManager::getInstance()->isThisTheMessageThread()) @@ -1264,6 +1277,8 @@ void AudioProcessorGraph::releaseResources() { const ScopedLock sl (getCallbackLock()); + cancelPendingUpdate(); + isPrepared = 0; for (auto* n : nodes) @@ -1304,11 +1319,11 @@ template static void processBlockForBuffer (AudioBuffer& buffer, MidiBuffer& midiMessages, AudioProcessorGraph& graph, std::unique_ptr& renderSequence, - Atomic& isPrepared) + std::atomic& isPrepared) { if (graph.isNonRealtime()) { - while (isPrepared.get() == 0) + while (! isPrepared) Thread::sleep (1); const ScopedLock sl (graph.getCallbackLock()); @@ -1320,7 +1335,7 @@ static void processBlockForBuffer (AudioBuffer& buffer, MidiBuffer& m { const ScopedLock sl (graph.getCallbackLock()); - if (isPrepared.get() == 1) + if (isPrepared) { if (renderSequence != nullptr) renderSequence->perform (buffer, midiMessages, graph.getPlayHead()); @@ -1335,7 +1350,7 @@ static void processBlockForBuffer (AudioBuffer& buffer, MidiBuffer& m void AudioProcessorGraph::processBlock (AudioBuffer& buffer, MidiBuffer& midiMessages) { - if (isPrepared.get() == 0 && MessageManager::getInstance()->isThisTheMessageThread()) + if ((! isPrepared) && MessageManager::getInstance()->isThisTheMessageThread()) handleAsyncUpdate(); processBlockForBuffer (buffer, midiMessages, *this, renderSequenceFloat, isPrepared); @@ -1343,7 +1358,7 @@ void AudioProcessorGraph::processBlock (AudioBuffer& buffer, MidiBuffer& void AudioProcessorGraph::processBlock (AudioBuffer& buffer, MidiBuffer& midiMessages) { - if (isPrepared.get() == 0 && MessageManager::getInstance()->isThisTheMessageThread()) + if ((! isPrepared) && MessageManager::getInstance()->isThisTheMessageThread()) handleAsyncUpdate(); processBlockForBuffer (buffer, midiMessages, *this, renderSequenceDouble, isPrepared); diff --git a/modules/juce_audio_processors/processors/juce_AudioProcessorGraph.h b/modules/juce_audio_processors/processors/juce_AudioProcessorGraph.h index f7ce5789..bb28badf 100644 --- a/modules/juce_audio_processors/processors/juce_AudioProcessorGraph.h +++ b/modules/juce_audio_processors/processors/juce_AudioProcessorGraph.h @@ -132,6 +132,8 @@ public: private: //============================================================================== friend class AudioProcessorGraph; + template + friend struct GraphRenderSequence; struct Connection { @@ -143,7 +145,8 @@ public: const std::unique_ptr processor; Array inputs, outputs; - bool isPrepared = false, bypassed = false; + bool isPrepared = false; + std::atomic bypassed { false }; Node (NodeID, std::unique_ptr) noexcept; @@ -151,6 +154,22 @@ public: void prepare (double newSampleRate, int newBlockSize, AudioProcessorGraph*, ProcessingPrecision); void unprepare(); + template + void processBlock (AudioBuffer& audio, MidiBuffer& midi) + { + const ScopedLock lock (processorLock); + processor->processBlock (audio, midi); + } + + template + void processBlockBypassed (AudioBuffer& audio, MidiBuffer& midi) + { + const ScopedLock lock (processorLock); + processor->processBlockBypassed (audio, midi); + } + + CriticalSection processorLock; + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Node) }; @@ -210,8 +229,8 @@ public: added a processor to the graph, the graph owns it and will delete it later when it is no longer needed. - The optional nodeId parameter lets you specify an ID to use for the node, but - if the value is already in use, this new node will overwrite the old one. + The optional nodeId parameter lets you specify a unique ID to use for the node. + If the value is already in use, this method will fail and return an empty node. If this succeeds, it returns a pointer to the newly-created node. */ @@ -396,7 +415,7 @@ private: friend class AudioGraphIOProcessor; - Atomic isPrepared { 0 }; + std::atomic isPrepared { false }; void topologyChanged(); void handleAsyncUpdate() override; diff --git a/modules/juce_audio_processors/processors/juce_AudioProcessorParameter.h b/modules/juce_audio_processors/processors/juce_AudioProcessorParameter.h index 1d3b3900..8552d7d3 100644 --- a/modules/juce_audio_processors/processors/juce_AudioProcessorParameter.h +++ b/modules/juce_audio_processors/processors/juce_AudioProcessorParameter.h @@ -205,7 +205,7 @@ public: /** Returns the current value of the parameter as a String. This function can be called when you are hosting plug-ins to get a - more specialsed textual represenation of the current value from the + more specialised textual representation of the current value from the plug-in, for example "On" rather than "1.0". If you are implementing a plug-in then you should ignore this function diff --git a/modules/juce_audio_processors/processors/juce_AudioProcessorParameterGroup.cpp b/modules/juce_audio_processors/processors/juce_AudioProcessorParameterGroup.cpp index cc2a75a4..62216b3c 100644 --- a/modules/juce_audio_processors/processors/juce_AudioProcessorParameterGroup.cpp +++ b/modules/juce_audio_processors/processors/juce_AudioProcessorParameterGroup.cpp @@ -97,6 +97,8 @@ String AudioProcessorParameterGroup::getName() const String AudioProcessorParameterGroup::getSeparator() const { return separator; } const AudioProcessorParameterGroup* AudioProcessorParameterGroup::getParent() const noexcept { return parent; } +void AudioProcessorParameterGroup::setName (String newName) { name = std::move (newName); } + const AudioProcessorParameterGroup::AudioProcessorParameterNode* const* AudioProcessorParameterGroup::begin() const noexcept { return const_cast (children.begin()); } const AudioProcessorParameterGroup::AudioProcessorParameterNode* const* AudioProcessorParameterGroup::end() const noexcept { return const_cast (children.end()); } diff --git a/modules/juce_audio_processors/processors/juce_AudioProcessorParameterGroup.h b/modules/juce_audio_processors/processors/juce_AudioProcessorParameterGroup.h index f0137f92..6c1580ad 100644 --- a/modules/juce_audio_processors/processors/juce_AudioProcessorParameterGroup.h +++ b/modules/juce_audio_processors/processors/juce_AudioProcessorParameterGroup.h @@ -143,9 +143,17 @@ public: addChild (std::forward (remainingChildren)...); } + /** Once a group has been added to an AudioProcessor don't try to mutate it by + moving or swapping it - this will crash most hosts. + */ AudioProcessorParameterGroup (AudioProcessorParameterGroup&&); + + /** Once a group has been added to an AudioProcessor don't try to mutate it by + moving or swapping it - this will crash most hosts. + */ AudioProcessorParameterGroup& operator= (AudioProcessorParameterGroup&&); + /** Destructor. */ ~AudioProcessorParameterGroup(); //============================================================================== @@ -158,9 +166,16 @@ public: /** Returns the group's separator string. */ String getSeparator() const; - /** Returns the parent of the group, or nullptr if this is a top-levle group. */ + /** Returns the parent of the group, or nullptr if this is a top-level group. */ const AudioProcessorParameterGroup* getParent() const noexcept; + //============================================================================== + /** Changes the name of the group. If you do this after the group has been added + to an AudioProcessor, call updateHostDisplay() to inform the host of the + change. Not all hosts support dynamic group name changes. + */ + void setName (String newName); + //============================================================================== const AudioProcessorParameterNode* const* begin() const noexcept; const AudioProcessorParameterNode* const* end() const noexcept; @@ -186,7 +201,11 @@ public: Array getGroupsForParameter (AudioProcessorParameter*) const; //============================================================================== - /** Adds a child to the group. */ + /** Adds a child to the group. + + Do not add children to a group which has itself already been added to the + AudioProcessor - the new elements will be ignored. + */ template void addChild (std::unique_ptr child) { @@ -196,7 +215,11 @@ public: append (std::move (child)); } - /** Adds multiple parameters or sub-groups to this group. */ + /** Adds multiple parameters or sub-groups to this group. + + Do not add children to a group which has itself already been added to the + AudioProcessor - the new elements will be ignored. + */ template void addChild (std::unique_ptr firstChild, Args&&... remainingChildren) { @@ -205,8 +228,10 @@ public: } #ifndef DOXYGEN - // This class now has a move operator, so if you're try to move them around, you should - // use that, or if you really need to swap two groups, just call std::swap + // This class now has a move operator, so if you're trying to move them around, you + // should use that, or if you really need to swap two groups, just call std::swap. + // However, remember that swapping a group that's already owned by an AudioProcessor + // will most likely crash the host, so don't do that. JUCE_DEPRECATED_WITH_BODY (void swapWith (AudioProcessorParameterGroup& other), { std::swap (*this, other); }) #endif diff --git a/modules/juce_audio_processors/processors/juce_GenericAudioProcessorEditor.cpp b/modules/juce_audio_processors/processors/juce_GenericAudioProcessorEditor.cpp index 9cb96927..08fb9a5d 100644 --- a/modules/juce_audio_processors/processors/juce_GenericAudioProcessorEditor.cpp +++ b/modules/juce_audio_processors/processors/juce_GenericAudioProcessorEditor.cpp @@ -485,7 +485,7 @@ public: height += comp->getHeight(); } - setSize (maxWidth, jmax (height, 100)); + setSize (maxWidth, jmax (height, 125)); } ~ParametersPanel() override diff --git a/modules/juce_audio_processors/scanning/juce_PluginListComponent.cpp b/modules/juce_audio_processors/scanning/juce_PluginListComponent.cpp index 9e76edc2..2c120c4b 100644 --- a/modules/juce_audio_processors/scanning/juce_PluginListComponent.cpp +++ b/modules/juce_audio_processors/scanning/juce_PluginListComponent.cpp @@ -398,7 +398,7 @@ public: // You need to use at least one thread when scanning plug-ins asynchronously jassert (! allowAsync || (numThreads > 0)); - // If the filesOrIdentifiersToScan argumnent isn't empty, we should only scan these + // If the filesOrIdentifiersToScan argument isn't empty, we should only scan these // If the path is empty, then paths aren't used for this format. if (filesOrIdentifiersToScan.isEmpty() && path.getNumPaths() > 0) { diff --git a/modules/juce_audio_processors/utilities/juce_AudioParameterBool.cpp b/modules/juce_audio_processors/utilities/juce_AudioParameterBool.cpp index 388e194c..ca3fcff6 100644 --- a/modules/juce_audio_processors/utilities/juce_AudioParameterBool.cpp +++ b/modules/juce_audio_processors/utilities/juce_AudioParameterBool.cpp @@ -69,7 +69,13 @@ AudioParameterBool::AudioParameterBool (const String& idToUse, const String& nam } } -AudioParameterBool::~AudioParameterBool() {} +AudioParameterBool::~AudioParameterBool() +{ + #if __cpp_lib_atomic_is_always_lock_free + static_assert (std::atomic::is_always_lock_free, + "AudioParameterBool requires a lock-free std::atomic"); + #endif +} float AudioParameterBool::getValue() const { return value; } void AudioParameterBool::setValue (float newValue) { value = newValue; valueChanged (get()); } diff --git a/modules/juce_audio_processors/utilities/juce_AudioParameterBool.h b/modules/juce_audio_processors/utilities/juce_AudioParameterBool.h index 1f728404..f43ec750 100644 --- a/modules/juce_audio_processors/utilities/juce_AudioParameterBool.h +++ b/modules/juce_audio_processors/utilities/juce_AudioParameterBool.h @@ -88,7 +88,7 @@ private: float getValueForText (const String&) const override; const NormalisableRange range { 0.0f, 1.0f, 1.0f }; - float value; + std::atomic value; const float defaultValue; std::function stringFromBoolFunction; std::function boolFromStringFunction; diff --git a/modules/juce_audio_processors/utilities/juce_AudioParameterChoice.cpp b/modules/juce_audio_processors/utilities/juce_AudioParameterChoice.cpp index 3cf79991..121f837d 100644 --- a/modules/juce_audio_processors/utilities/juce_AudioParameterChoice.cpp +++ b/modules/juce_audio_processors/utilities/juce_AudioParameterChoice.cpp @@ -55,7 +55,13 @@ AudioParameterChoice::AudioParameterChoice (const String& idToUse, const String& indexFromStringFunction = [this] (const String& text) { return choices.indexOf (text); }; } -AudioParameterChoice::~AudioParameterChoice() {} +AudioParameterChoice::~AudioParameterChoice() +{ + #if __cpp_lib_atomic_is_always_lock_free + static_assert (std::atomic::is_always_lock_free, + "AudioParameterChoice requires a lock-free std::atomic"); + #endif +} float AudioParameterChoice::getValue() const { return convertTo0to1 (value); } void AudioParameterChoice::setValue (float newValue) { value = convertFrom0to1 (newValue); valueChanged (getIndex()); } diff --git a/modules/juce_audio_processors/utilities/juce_AudioParameterChoice.h b/modules/juce_audio_processors/utilities/juce_AudioParameterChoice.h index 32b30e7b..e0d242db 100644 --- a/modules/juce_audio_processors/utilities/juce_AudioParameterChoice.h +++ b/modules/juce_audio_processors/utilities/juce_AudioParameterChoice.h @@ -63,7 +63,7 @@ public: ~AudioParameterChoice() override; /** Returns the current index of the selected item. */ - int getIndex() const noexcept { return roundToInt (value); } + int getIndex() const noexcept { return roundToInt (value.load()); } /** Returns the current index of the selected item. */ operator int() const noexcept { return getIndex(); } @@ -100,7 +100,7 @@ private: float getValueForText (const String&) const override; const NormalisableRange range; - float value; + std::atomic value; const float defaultValue; std::function stringFromIndexFunction; std::function indexFromStringFunction; diff --git a/modules/juce_audio_processors/utilities/juce_AudioParameterFloat.cpp b/modules/juce_audio_processors/utilities/juce_AudioParameterFloat.cpp index f209ccc6..894cf4ea 100644 --- a/modules/juce_audio_processors/utilities/juce_AudioParameterFloat.cpp +++ b/modules/juce_audio_processors/utilities/juce_AudioParameterFloat.cpp @@ -76,7 +76,13 @@ AudioParameterFloat::AudioParameterFloat (String pid, String nm, float minValue, { } -AudioParameterFloat::~AudioParameterFloat() {} +AudioParameterFloat::~AudioParameterFloat() +{ + #if __cpp_lib_atomic_is_always_lock_free + static_assert (std::atomic::is_always_lock_free, + "AudioParameterFloat requires a lock-free std::atomic"); + #endif +} float AudioParameterFloat::getValue() const { return convertTo0to1 (value); } void AudioParameterFloat::setValue (float newValue) { value = convertFrom0to1 (newValue); valueChanged (get()); } diff --git a/modules/juce_audio_processors/utilities/juce_AudioParameterFloat.h b/modules/juce_audio_processors/utilities/juce_AudioParameterFloat.h index 57c2ae09..62700c44 100644 --- a/modules/juce_audio_processors/utilities/juce_AudioParameterFloat.h +++ b/modules/juce_audio_processors/utilities/juce_AudioParameterFloat.h @@ -106,7 +106,7 @@ private: String getText (float, int) const override; float getValueForText (const String&) const override; - float value; + std::atomic value; const float defaultValue; std::function stringFromValueFunction; std::function valueFromStringFunction; diff --git a/modules/juce_audio_processors/utilities/juce_AudioParameterInt.cpp b/modules/juce_audio_processors/utilities/juce_AudioParameterInt.cpp index 53a78f9a..913bcf36 100644 --- a/modules/juce_audio_processors/utilities/juce_AudioParameterInt.cpp +++ b/modules/juce_audio_processors/utilities/juce_AudioParameterInt.cpp @@ -56,7 +56,13 @@ AudioParameterInt::AudioParameterInt (const String& idToUse, const String& nameT intFromStringFunction = [] (const String& text) { return text.getIntValue(); }; } -AudioParameterInt::~AudioParameterInt() {} +AudioParameterInt::~AudioParameterInt() +{ + #if __cpp_lib_atomic_is_always_lock_free + static_assert (std::atomic::is_always_lock_free, + "AudioParameterInt requires a lock-free std::atomic"); + #endif +} float AudioParameterInt::getValue() const { return convertTo0to1 (value); } void AudioParameterInt::setValue (float newValue) { value = convertFrom0to1 (newValue); valueChanged (get()); } diff --git a/modules/juce_audio_processors/utilities/juce_AudioParameterInt.h b/modules/juce_audio_processors/utilities/juce_AudioParameterInt.h index 610feb18..868e28ca 100644 --- a/modules/juce_audio_processors/utilities/juce_AudioParameterInt.h +++ b/modules/juce_audio_processors/utilities/juce_AudioParameterInt.h @@ -64,7 +64,7 @@ public: ~AudioParameterInt() override; /** Returns the parameter's current value as an integer. */ - int get() const noexcept { return roundToInt (value); } + int get() const noexcept { return roundToInt (value.load()); } /** Returns the parameter's current value as an integer. */ operator int() const noexcept { return get(); } @@ -96,7 +96,7 @@ private: float getValueForText (const String&) const override; const NormalisableRange range; - float value; + std::atomic value; const float defaultValue; std::function stringFromIntFunction; std::function intFromStringFunction; diff --git a/modules/juce_audio_processors/utilities/juce_AudioProcessorValueTreeState.cpp b/modules/juce_audio_processors/utilities/juce_AudioProcessorValueTreeState.cpp index ad36c5aa..252dad8f 100644 --- a/modules/juce_audio_processors/utilities/juce_AudioProcessorValueTreeState.cpp +++ b/modules/juce_audio_processors/utilities/juce_AudioProcessorValueTreeState.cpp @@ -124,8 +124,8 @@ public: return parameter.getText (normalise (value), 0); } - float getDenormalisedValue() const { return unnormalisedValue; } - float& getRawDenormalisedValue() { return unnormalisedValue; } + float getDenormalisedValue() const { return unnormalisedValue; } + std::atomic& getRawDenormalisedValue() { return unnormalisedValue; } bool flushToTree (const Identifier& key, UndoManager* um) { @@ -139,12 +139,12 @@ public: if ((float) *valueProperty != unnormalisedValue) { ScopedValueSetter svs (ignoreParameterChangedCallbacks, true); - tree.setProperty (key, unnormalisedValue, um); + tree.setProperty (key, unnormalisedValue.load(), um); } } else { - tree.setProperty (key, unnormalisedValue, nullptr); + tree.setProperty (key, unnormalisedValue.load(), nullptr); } return true; @@ -188,7 +188,7 @@ private: RangedAudioParameter& parameter; ListenerList listeners; - float unnormalisedValue{}; + std::atomic unnormalisedValue{}; std::atomic needsUpdate { true }; bool listenersNeedCalling { true }, ignoreParameterChangedCallbacks { false }; }; @@ -258,7 +258,10 @@ AudioProcessorValueTreeState::AudioProcessorValueTreeState (AudioProcessor& p, U state.addListener (this); } -AudioProcessorValueTreeState::~AudioProcessorValueTreeState() {} +AudioProcessorValueTreeState::~AudioProcessorValueTreeState() +{ + stopTimer(); +} //============================================================================== RangedAudioParameter* AudioProcessorValueTreeState::createAndAddParameter (const String& paramID, @@ -355,7 +358,7 @@ RangedAudioParameter* AudioProcessorValueTreeState::getParameter (StringRef para return nullptr; } -float* AudioProcessorValueTreeState::getRawParameterValue (StringRef paramID) const noexcept +std::atomic* AudioProcessorValueTreeState::getRawParameterValue (StringRef paramID) const noexcept { if (auto* p = getParameterAdapter (paramID)) return &p->getRawDenormalisedValue(); @@ -791,7 +794,7 @@ struct ParameterAdapterTests : public UnitTest adapter.setDenormalisedValue (value); expectEquals (adapter.getDenormalisedValue(), value); - expectEquals (adapter.getRawDenormalisedValue(), value); + expectEquals (adapter.getRawDenormalisedValue().load(), value); }; test ({ -20, -10 }, -15); @@ -1044,7 +1047,7 @@ public: const auto value = 0.5f; param->setValueNotifyingHost (value); - expectEquals (*proc.state.getRawParameterValue (key), value); + expectEquals (proc.state.getRawParameterValue (key)->load(), value); } beginTest ("After adding an APVTS::Parameter, its value is the default value"); @@ -1062,7 +1065,7 @@ public: nullptr, nullptr)); - expectEquals (*proc.state.getRawParameterValue (key), value); + expectEquals (proc.state.getRawParameterValue (key)->load(), value); } beginTest ("Listeners receive notifications when parameters change"); @@ -1138,7 +1141,7 @@ public: value = newValue; expectEquals (param->getValue(), newValue); - expectEquals (*proc.state.getRawParameterValue (key), newValue); + expectEquals (proc.state.getRawParameterValue (key)->load(), newValue); } beginTest ("When the parameter value is changed, custom parameter values are updated"); @@ -1154,7 +1157,7 @@ public: value = newValue; expectEquals (paramPtr->getCurrentChoiceName(), choices[int (newValue)]); - expectEquals (*proc.state.getRawParameterValue (key), newValue); + expectEquals (proc.state.getRawParameterValue (key)->load(), newValue); } beginTest ("When the parameter value is changed, listeners are notified"); diff --git a/modules/juce_audio_processors/utilities/juce_AudioProcessorValueTreeState.h b/modules/juce_audio_processors/utilities/juce_AudioProcessorValueTreeState.h index f1ee8a43..f06a70ba 100644 --- a/modules/juce_audio_processors/utilities/juce_AudioProcessorValueTreeState.h +++ b/modules/juce_audio_processors/utilities/juce_AudioProcessorValueTreeState.h @@ -285,7 +285,7 @@ public: Note that calling this method from within AudioProcessorValueTreeState::Listener::parameterChanged() is not guaranteed to return an up-to-date value for the parameter. */ - float* getRawParameterValue (StringRef parameterID) const noexcept; + std::atomic* getRawParameterValue (StringRef parameterID) const noexcept; //============================================================================== /** A listener class that can be attached to an AudioProcessorValueTreeState. diff --git a/modules/juce_audio_utils/gui/juce_AudioAppComponent.h b/modules/juce_audio_utils/gui/juce_AudioAppComponent.h index 30363206..e64eeccc 100644 --- a/modules/juce_audio_utils/gui/juce_AudioAppComponent.h +++ b/modules/juce_audio_utils/gui/juce_AudioAppComponent.h @@ -61,7 +61,7 @@ public: An AudioSource has two states: prepared and unprepared. - The prepareToPlay() method is guaranteed to be called at least once on an 'unpreprared' + The prepareToPlay() method is guaranteed to be called at least once on an 'unprepared' source to put it into a 'prepared' state before any calls will be made to getNextAudioBlock(). This callback allows the source to initialise any resources it might need when playing. diff --git a/modules/juce_audio_utils/juce_audio_utils.h b/modules/juce_audio_utils/juce_audio_utils.h index e346c70b..95f06f3a 100644 --- a/modules/juce_audio_utils/juce_audio_utils.h +++ b/modules/juce_audio_utils/juce_audio_utils.h @@ -24,6 +24,7 @@ ============================================================================== */ + /******************************************************************************* The block below describes the properties of this module, and is read by the Projucer to automatically generate project code that uses it. @@ -33,17 +34,17 @@ BEGIN_JUCE_MODULE_DECLARATION - ID: juce_audio_utils - vendor: juce - version: 5.4.5 - name: JUCE extra audio utility classes - description: Classes for audio-related GUI and miscellaneous tasks. - website: http://www.juce.com/juce - license: GPL/Commercial - - dependencies: juce_gui_extra, juce_audio_processors, juce_audio_formats, juce_audio_devices - OSXFrameworks: CoreAudioKit DiscRecording - iOSFrameworks: CoreAudioKit + ID: juce_audio_utils + vendor: juce + version: 5.4.6 + name: JUCE extra audio utility classes + description: Classes for audio-related GUI and miscellaneous tasks. + website: http://www.juce.com/juce + license: GPL/Commercial + + dependencies: juce_gui_extra, juce_audio_processors, juce_audio_formats, juce_audio_devices + OSXFrameworks: CoreAudioKit DiscRecording + iOSFrameworks: CoreAudioKit END_JUCE_MODULE_DECLARATION diff --git a/modules/juce_blocks_basics/blocks/juce_Block.h b/modules/juce_blocks_basics/blocks/juce_Block.h index 41def683..b4717c94 100644 --- a/modules/juce_blocks_basics/blocks/juce_Block.h +++ b/modules/juce_blocks_basics/blocks/juce_Block.h @@ -46,7 +46,8 @@ public: loopBlock, /**< Loop control block type. */ developerControlBlock, /**< Developer control block type. */ touchBlock, /**< Touch control block type. */ - seaboardBlock /**< Seaboard block type. */ + seaboardBlock, /**< Seaboard block type. */ + lumiKeysBlock /**< LUMI Keys block type */ }; /** The Block class is reference-counted, so always use a Block::Ptr when @@ -457,7 +458,7 @@ public: /** Provides a callback that will be called when a config changes. */ virtual void setConfigChangedCallback (std::function) = 0; - /** Provides a callback that will be called when a prgoram has been loaded. */ + /** Provides a callback that will be called when a program has been loaded. */ virtual void setProgramLoadedCallback (std::function programLoaded) = 0; //============================================================================== diff --git a/modules/juce_blocks_basics/blocks/juce_BlockConfigManager.h b/modules/juce_blocks_basics/blocks/juce_BlockConfigManager.h index e93e5857..b314ce8e 100644 --- a/modules/juce_blocks_basics/blocks/juce_BlockConfigManager.h +++ b/modules/juce_blocks_basics/blocks/juce_BlockConfigManager.h @@ -44,11 +44,6 @@ using ConfigType = Block::ConfigMetaData::ConfigType; */ struct BlockConfigManager { - void setDeviceIndex (TopologyIndex newDeviceIndex) { deviceIndex = newDeviceIndex; } - void setDeviceComms (PhysicalTopologySource::DeviceConnection* newConn) { deviceConnection = newConn; } - - static constexpr uint32 numConfigItems = 69; - /** Structure describing a configuration */ struct ConfigDescription { @@ -70,102 +65,122 @@ struct BlockConfigManager } }; + BlockConfigManager (Array defaultConfig) + { + for (auto c : defaultConfig) + { + uint32 itemIndex; + + if (getIndexForItem (c.item, itemIndex)) + configList[itemIndex] = c; + } + } + + void setDeviceIndex (TopologyIndex newDeviceIndex) { deviceIndex = newDeviceIndex; } + void setDeviceComms (PhysicalTopologySource::DeviceConnection* newConn) { deviceConnection = newConn; } + + static constexpr uint32 numConfigItems = 69; + + static constexpr const char* midiSettingsGroup = "MIDI Settings"; + static constexpr const char* pitchGroup = "Pitch"; + static constexpr const char* playGroup = "Play mode"; + static constexpr const char* sensitivityGroup = "Sensitivity"; + static constexpr const char* rhythmGroup = "Rhythm"; + static constexpr const char* coloursGroup = "Colors"; + ConfigDescription configList[numConfigItems] = { - { midiStartChannel, 2, 1, 16, false, "MIDI Start Channel", ConfigType::integer, {}, "MIDI Settings" }, - { midiEndChannel, 16, 1, 16, false, "MIDI End Channel", ConfigType::integer, {}, "MIDI Settings" }, - { midiUseMPE, 1, 0, 2, false, "MIDI Mode", ConfigType::options, { "Multi Channel", + { midiStartChannel, 2, 1, 16, false, "MIDI Start Channel", ConfigType::integer, {}, midiSettingsGroup }, + { midiEndChannel, 16, 1, 16, false, "MIDI End Channel", ConfigType::integer, {}, midiSettingsGroup }, + { midiUseMPE, 1, 0, 2, false, "MIDI Mode", ConfigType::options, { "Multi Channel", "MPE", - "Single Channel" }, "MIDI Settings" }, - { pitchBendRange, 48, 1, 96, false, "Pitch Bend Range", ConfigType::integer, {}, "MIDI Settings" }, - { midiChannelRange, 15, 1, 15, false, "No. MIDI Channels", ConfigType::integer, {}, "MIDI Settings" }, - { MPEZone, 0, 0, 1, false, "MPE Zone", ConfigType::options, { "Lower Zone", - "Upper Zone"}, "MIDI Settings" }, - { octave, 0, -4, 6, false, "Octave", ConfigType::integer, {}, "Pitch" }, - { transpose, 0, -11, 11, false, "Transpose", ConfigType::integer, {}, "Pitch" }, - { slideCC, 74, 0, 127, false, "Slide CC", ConfigType::integer, {}, "Play mode" }, - { slideMode, 0, 0, 2, false, "Slide Mode", ConfigType::options, { "Absolute", + "Single Channel" }, midiSettingsGroup }, + { pitchBendRange, 48, 1, 96, false, "Pitch Bend Range", ConfigType::integer, {}, midiSettingsGroup }, + { midiChannelRange, 15, 1, 15, false, "No. MIDI Channels", ConfigType::integer, {}, midiSettingsGroup }, + { MPEZone, 0, 0, 1, false, "MPE Zone", ConfigType::options, { "Lower Zone", + "Upper Zone"}, midiSettingsGroup }, + { octave, 0, -4, 6, false, "Octave", ConfigType::integer, {}, pitchGroup }, + { transpose, 0, -11, 11, false, "Transpose", ConfigType::integer, {}, pitchGroup }, + { slideCC, 74, 0, 127, false, "Slide CC", ConfigType::integer, {}, playGroup }, + { slideMode, 0, 0, 2, false, "Slide Mode", ConfigType::options, { "Absolute", "Relative Unipolar", - "Relative Bipolar" }, "Play mode" }, - { velocitySensitivity, 100, 0, 127, false, "Strike Sensitivity", ConfigType::integer, {}, "5D Touch" }, - { glideSensitivity, 100, 0, 127, false, "Glide Sensitivity", ConfigType::integer, {}, "5D Touch" }, - { slideSensitivity, 100, 0, 127, false, "Slide Sensitivity", ConfigType::integer, {}, "5D Touch" }, - { pressureSensitivity, 100, 0, 127, false, "Pressure Sensitivity", ConfigType::integer, {}, "5D Touch" }, - { liftSensitivity, 100, 0, 127, false, "Lift Sensitivity", ConfigType::integer, {}, "5D Touch" }, - { fixedVelocity, 0, 0, 1, false, "Fixed Velocity", ConfigType::boolean, {}, "5D Touch" }, - { fixedVelocityValue, 127, 1, 127, false, "Fixed Velocity Value", ConfigType::integer, {}, "5D Touch" }, - { pianoMode, 0, 0, 1, false, "Piano Mode", ConfigType::boolean, {}, "Play mode" }, - { glideLock, 0, 0, 127, false, "Glide Rate", ConfigType::integer, {}, "Play mode" }, - { glideLockEnable, 0, 0, 1, false, "Glide Lock Enable", ConfigType::boolean, {}, "Play mode" }, - { mode, 4, 1, 5, false, "Mode", ConfigType::integer, {}, "Play mode" }, - { volume, 100, 0, 127, false, "Volume", ConfigType::integer, {}, "Play mode" }, - { scale, 0, 0, 18, false, "Scale", ConfigType::integer, {}, "Play mode" }, // NOTE: Should be options - { key, 0, 0, 11, false, "Key", ConfigType::options, { "C", "C#", "D", "D#", - "E", "F", "F#", "G", - "G#", "A", "A#", "B"}, "Play mode" }, - { hideMode, 0, 0, 1, false, "Hide Mode", ConfigType::boolean, {}, "Play mode" }, - { chord, 0, 0, 127, false, "Chord", ConfigType::integer, {}, "Play mode" }, // NOTE: Should be options - { arpPattern, 0, 0, 127, false, "Arp Pattern", ConfigType::integer, {}, "Play mode" }, - { tempo, 120, 1, 300, false, "Tempo", ConfigType::integer, {}, "Rhythm" }, - { key, 0, 0, 11, false, "Key", ConfigType::options, { "C", "C#", "D", "D#", + "Relative Bipolar" }, playGroup }, + { velocitySensitivity, 100, 0, 127, false, "Strike Sensitivity", ConfigType::integer, {}, sensitivityGroup }, + { glideSensitivity, 100, 0, 127, false, "Glide Sensitivity", ConfigType::integer, {}, sensitivityGroup }, + { slideSensitivity, 100, 0, 127, false, "Slide Sensitivity", ConfigType::integer, {}, sensitivityGroup }, + { pressureSensitivity, 100, 0, 127, false, "Pressure Sensitivity", ConfigType::integer, {}, sensitivityGroup }, + { liftSensitivity, 100, 0, 127, false, "Lift Sensitivity", ConfigType::integer, {}, sensitivityGroup }, + { fixedVelocity, 0, 0, 1, false, "Fixed Velocity", ConfigType::boolean, {}, sensitivityGroup }, + { fixedVelocityValue, 127, 1, 127, false, "Fixed Velocity Value", ConfigType::integer, {}, sensitivityGroup }, + { pianoMode, 0, 0, 1, false, "Piano Mode", ConfigType::boolean, {}, playGroup }, + { glideLock, 0, 0, 127, false, "Glide Rate", ConfigType::integer, {}, playGroup }, + { glideLockEnable, 0, 0, 1, false, "Glide Lock Enable", ConfigType::boolean, {}, playGroup }, + { mode, 4, 1, 5, false, "Mode", ConfigType::integer, {}, playGroup }, + { volume, 100, 0, 127, false, "Volume", ConfigType::integer, {}, playGroup }, + { scale, 0, 0, 18, false, "Scale", ConfigType::integer, {}, playGroup }, // NOTE: Should be options + { hideMode, 0, 0, 1, false, "Hide Mode", ConfigType::boolean, {}, playGroup }, + { chord, 0, 0, 127, false, "Chord", ConfigType::integer, {}, playGroup }, // NOTE: Should be options + { arpPattern, 0, 0, 127, false, "Arp Pattern", ConfigType::integer, {}, playGroup }, + { tempo, 120, 1, 300, false, "Tempo", ConfigType::integer, {}, rhythmGroup }, + { key, 0, 0, 11, false, "Key", ConfigType::options, { "C", "C#", "D", "D#", "E", "F", "F#", "G", - "G#", "A", "A#", "B"}, "Play mode" }, - { autoTransposeToKey, 0, 0, 1, false, "Auto Transpose To Key",ConfigType::boolean, {}, "Pitch" }, - { xTrackingMode, 1, 1, 4, false, "Glide Tracking Mode", ConfigType::options, { "Multi-Channel", + "G#", "A", "A#", "B"}, playGroup }, + { autoTransposeToKey, 0, 0, 1, false, "Auto Transpose To Key",ConfigType::boolean, {}, pitchGroup }, + { xTrackingMode, 1, 1, 4, false, "Glide Tracking Mode", ConfigType::options, { "Multi-Channel", "Last Played", "Highest", "Lowest", - "Disabled" }, "Play mode" }, - { yTrackingMode, 1, 1, 4, false, "Slide Tracking Mode", ConfigType::options, { "Multi-Channel", + "Disabled" }, playGroup }, + { yTrackingMode, 1, 1, 4, false, "Slide Tracking Mode", ConfigType::options, { "Multi-Channel", "Last Played", "Highest", "Lowest", - "Disabled" }, "Play mode" }, - { zTrackingMode, 1, 0, 4, false, "Pressure Tracking Mode", ConfigType::options, { "Multi-Channel", + "Disabled" }, playGroup }, + { zTrackingMode, 1, 0, 4, false, "Pressure Tracking Mode", ConfigType::options, { "Poly Aftertouch", "Last Played", "Highest", "Lowest", "Disabled", - "Hardest" }, "Play mode" }, + "Hardest" }, playGroup }, - { gammaCorrection, 0, 0, 1, false, "Gamma Correction", ConfigType::boolean, {}, {} }, - { globalKeyColour, INT32_MIN, INT32_MIN, INT32_MAX, false, "Global Key Colour", ConfigType::colour, {}, "Colour" }, - { rootKeyColour, INT32_MIN, INT32_MIN, INT32_MAX, false, "Root Key Colour" , ConfigType::colour, {}, "Colour" }, - { brightness, 100, 0, 100, false, "Brightness", ConfigType::integer, {}, "Colour" }, + { gammaCorrection, 0, 0, 1, false, "Gamma Correction", ConfigType::boolean, {}, coloursGroup }, + { globalKeyColour, INT32_MIN, INT32_MIN, INT32_MAX, false, "Global Key Color", ConfigType::colour, {}, coloursGroup }, + { rootKeyColour, INT32_MIN, INT32_MIN, INT32_MAX, false, "Root Key Color" , ConfigType::colour, {}, coloursGroup }, + { brightness, 100, 0, 100, false, "Brightness", ConfigType::integer, {}, coloursGroup }, // These can be defined for unique usage for a given Littlefoot script - { user0, 0, 0, 127, false, {}, ConfigType::integer, {}, {} }, - { user1, 0, 0, 127, false, {}, ConfigType::integer, {}, {} }, - { user2, 0, 0, 127, false, {}, ConfigType::integer, {}, {} }, - { user3, 0, 0, 127, false, {}, ConfigType::integer, {}, {} }, - { user4, 0, 0, 127, false, {}, ConfigType::integer, {}, {} }, - { user5, 0, 0, 127, false, {}, ConfigType::integer, {}, {} }, - { user6, 0, 0, 127, false, {}, ConfigType::integer, {}, {} }, - { user7, 0, 0, 127, false, {}, ConfigType::integer, {}, {} }, - { user8, 0, 0, 127, false, {}, ConfigType::integer, {}, {} }, - { user9, 0, 0, 127, false, {}, ConfigType::integer, {}, {} }, - { user10, 0, 0, 127, false, {}, ConfigType::integer, {}, {} }, - { user11, 0, 0, 127, false, {}, ConfigType::integer, {}, {} }, - { user12, 0, 0, 127, false, {}, ConfigType::integer, {}, {} }, - { user13, 0, 0, 127, false, {}, ConfigType::integer, {}, {} }, - { user14, 0, 0, 127, false, {}, ConfigType::integer, {}, {} }, - { user15, 0, 0, 127, false, {}, ConfigType::integer, {}, {} }, - { user16, 0, 0, 127, false, {}, ConfigType::integer, {}, {} }, - { user17, 0, 0, 127, false, {}, ConfigType::integer, {}, {} }, - { user18, 0, 0, 127, false, {}, ConfigType::integer, {}, {} }, - { user19, 0, 0, 127, false, {}, ConfigType::integer, {}, {} }, - { user20, 0, 0, 127, false, {}, ConfigType::integer, {}, {} }, - { user21, 0, 0, 127, false, {}, ConfigType::integer, {}, {} }, - { user22, 0, 0, 127, false, {}, ConfigType::integer, {}, {} }, - { user23, 0, 0, 127, false, {}, ConfigType::integer, {}, {} }, - { user24, 0, 0, 127, false, {}, ConfigType::integer, {}, {} }, - { user25, 0, 0, 127, false, {}, ConfigType::integer, {}, {} }, - { user26, 0, 0, 127, false, {}, ConfigType::integer, {}, {} }, - { user27, 0, 0, 127, false, {}, ConfigType::integer, {}, {} }, - { user28, 0, 0, 127, false, {}, ConfigType::integer, {}, {} }, - { user29, 0, 0, 127, false, {}, ConfigType::integer, {}, {} }, - { user30, 0, 0, 127, false, {}, ConfigType::integer, {}, {} }, - { user31, 0, 0, 127, false, {}, ConfigType::integer, {}, {} } + { user0, 0, 0, 127, false, {}, ConfigType::integer, {}, {} }, + { user1, 0, 0, 127, false, {}, ConfigType::integer, {}, {} }, + { user2, 0, 0, 127, false, {}, ConfigType::integer, {}, {} }, + { user3, 0, 0, 127, false, {}, ConfigType::integer, {}, {} }, + { user4, 0, 0, 127, false, {}, ConfigType::integer, {}, {} }, + { user5, 0, 0, 127, false, {}, ConfigType::integer, {}, {} }, + { user6, 0, 0, 127, false, {}, ConfigType::integer, {}, {} }, + { user7, 0, 0, 127, false, {}, ConfigType::integer, {}, {} }, + { user8, 0, 0, 127, false, {}, ConfigType::integer, {}, {} }, + { user9, 0, 0, 127, false, {}, ConfigType::integer, {}, {} }, + { user10, 0, 0, 127, false, {}, ConfigType::integer, {}, {} }, + { user11, 0, 0, 127, false, {}, ConfigType::integer, {}, {} }, + { user12, 0, 0, 127, false, {}, ConfigType::integer, {}, {} }, + { user13, 0, 0, 127, false, {}, ConfigType::integer, {}, {} }, + { user14, 0, 0, 127, false, {}, ConfigType::integer, {}, {} }, + { user15, 0, 0, 127, false, {}, ConfigType::integer, {}, {} }, + { user16, 0, 0, 127, false, {}, ConfigType::integer, {}, {} }, + { user17, 0, 0, 127, false, {}, ConfigType::integer, {}, {} }, + { user18, 0, 0, 127, false, {}, ConfigType::integer, {}, {} }, + { user19, 0, 0, 127, false, {}, ConfigType::integer, {}, {} }, + { user20, 0, 0, 127, false, {}, ConfigType::integer, {}, {} }, + { user21, 0, 0, 127, false, {}, ConfigType::integer, {}, {} }, + { user22, 0, 0, 127, false, {}, ConfigType::integer, {}, {} }, + { user23, 0, 0, 127, false, {}, ConfigType::integer, {}, {} }, + { user24, 0, 0, 127, false, {}, ConfigType::integer, {}, {} }, + { user25, 0, 0, 127, false, {}, ConfigType::integer, {}, {} }, + { user26, 0, 0, 127, false, {}, ConfigType::integer, {}, {} }, + { user27, 0, 0, 127, false, {}, ConfigType::integer, {}, {} }, + { user28, 0, 0, 127, false, {}, ConfigType::integer, {}, {} }, + { user29, 0, 0, 127, false, {}, ConfigType::integer, {}, {} }, + { user30, 0, 0, 127, false, {}, ConfigType::integer, {}, {} }, + { user31, 0, 0, 127, false, {}, ConfigType::integer, {}, {} } }; //============================================================================== diff --git a/modules/juce_blocks_basics/blocks/juce_BlocksVersion.h b/modules/juce_blocks_basics/blocks/juce_BlocksVersion.h index 66f8bbf5..e20ad5f2 100644 --- a/modules/juce_blocks_basics/blocks/juce_BlocksVersion.h +++ b/modules/juce_blocks_basics/blocks/juce_BlocksVersion.h @@ -40,10 +40,10 @@ public: /** The release tag for this version, such as "beta", "alpha", "rc", etc */ String releaseType; - /** A numberical value assosiated with the release tag, such as "beta 4" */ + /** A numerical value associated with the release tag, such as "beta 4" */ int releaseCount = 0; - /** The assosiated git commit that generated this firmware version */ + /** The associated git commit that generated this firmware version */ String commit; /** Identify "forced" firmware builds **/ diff --git a/modules/juce_blocks_basics/blocks/juce_ControlButton.h b/modules/juce_blocks_basics/blocks/juce_ControlButton.h index 426a14a2..ec09b012 100644 --- a/modules/juce_blocks_basics/blocks/juce_ControlButton.h +++ b/modules/juce_blocks_basics/blocks/juce_ControlButton.h @@ -95,13 +95,13 @@ public: /** Returns the position of this button on the device, in device units. For buttons that are on the side of the device, this may want to return a value that - is beyond the phyiscal block size. + is beyond the physical block size. */ virtual float getPositionX() const = 0; /** Returns the position of this button on the device, in device units. For buttons that are on the side of the device, this may want to return a value that - is beyond the phyiscal block size. + is beyond the physical block size. */ virtual float getPositionY() const = 0; diff --git a/modules/juce_blocks_basics/blocks/juce_TouchList.h b/modules/juce_blocks_basics/blocks/juce_TouchList.h index 5f7287d9..30ee8306 100644 --- a/modules/juce_blocks_basics/blocks/juce_TouchList.h +++ b/modules/juce_blocks_basics/blocks/juce_TouchList.h @@ -130,7 +130,7 @@ public: TouchEntry* end() noexcept { return touches.end(); } const TouchEntry* end() const noexcept { return touches.end(); } - /** Retrieve a reference to particular item in the list of touch entires. */ + /** Retrieve a reference to particular item in the list of touch entries. */ TouchEntry& operator[] (const int index) { return touches.getReference (index); } /** Resets all contents, doest not generate any call-backs. */ diff --git a/modules/juce_blocks_basics/juce_blocks_basics.cpp b/modules/juce_blocks_basics/juce_blocks_basics.cpp index d833b3f1..132dcfe0 100644 --- a/modules/juce_blocks_basics/juce_blocks_basics.cpp +++ b/modules/juce_blocks_basics/juce_blocks_basics.cpp @@ -39,9 +39,8 @@ namespace juce #include "protocol/juce_BlocksProtocolDefinitions.h" #include "protocol/juce_HostPacketDecoder.h" #include "protocol/juce_HostPacketBuilder.h" -#include "protocol/juce_BlockModels.h" - #include "blocks/juce_BlockConfigManager.h" +#include "protocol/juce_BlockModels.h" #include "blocks/juce_Block.cpp" #include "blocks/juce_BlocksVersion.cpp" #include "topology/juce_BlockGraph.cpp" diff --git a/modules/juce_blocks_basics/juce_blocks_basics.h b/modules/juce_blocks_basics/juce_blocks_basics.h index aa8f3396..41035250 100644 --- a/modules/juce_blocks_basics/juce_blocks_basics.h +++ b/modules/juce_blocks_basics/juce_blocks_basics.h @@ -20,6 +20,7 @@ ============================================================================== */ + /******************************************************************************* The block below describes the properties of this module, and is read by the Projucer to automatically generate project code that uses it. @@ -31,14 +32,14 @@ ID: juce_blocks_basics vendor: juce - version: 5.4.5 + version: 5.4.6 name: Provides low-level control over ROLI BLOCKS devices description: JUCE wrapper for low-level control over ROLI BLOCKS devices. website: http://developer.roli.com license: ISC minimumCppStandard: 14 - dependencies: juce_events juce_audio_devices + dependencies: juce_events juce_audio_devices END_JUCE_MODULE_DECLARATION diff --git a/modules/juce_blocks_basics/protocol/juce_BlockModels.h b/modules/juce_blocks_basics/protocol/juce_BlockModels.h index d22f5051..709697ad 100644 --- a/modules/juce_blocks_basics/protocol/juce_BlockModels.h +++ b/modules/juce_blocks_basics/protocol/juce_BlockModels.h @@ -33,12 +33,13 @@ struct BlockDataSheet { BlockDataSheet (const BlocksProtocol::BlockSerialNumber& serial) : serialNumber (serial) { - if (serialNumber.isPadBlock()) initialiseForPadBlock2x2(); - if (serialNumber.isLiveBlock()) initialiseForControlBlockLive(); - if (serialNumber.isLoopBlock()) initialiseForControlBlockLoop(); - if (serialNumber.isDevCtrlBlock()) initialiseForControlBlockDeveloper(); - if (serialNumber.isTouchBlock()) initialiseForControlBlockTouch(); - if (serialNumber.isSeaboardBlock()) initialiseForSeaboardBlock(); + if (serialNumber.isPadBlock()) initialiseForPadBlock2x2(); + if (serialNumber.isLiveBlock()) initialiseForControlBlockLive(); + if (serialNumber.isLoopBlock()) initialiseForControlBlockLoop(); + if (serialNumber.isDevCtrlBlock()) initialiseForControlBlockDeveloper(); + if (serialNumber.isTouchBlock()) initialiseForControlBlockTouch(); + if (serialNumber.isSeaboardBlock()) initialiseForSeaboardBlock(); + if (serialNumber.isLumiKeysBlock()) initialiseForLumiKeysBlock(); } Block::ConnectionPort convertPortIndexToConnectorPort (BlocksProtocol::ConnectorPort port) const noexcept @@ -78,6 +79,7 @@ struct BlockDataSheet Array statusLEDs; Array ports; Array dials; + Array defaultConfig; private: //============================================================================== @@ -224,6 +226,45 @@ private: addModeButton(); } + void initialiseForLumiKeysBlock() + { + apiType = Block::Type::lumiKeysBlock; + + description = "LUMI Keys BLOCK (6x3)"; + + widthUnits = 6; + heightUnits = 3; + + lightGridWidth = 0; + lightGridHeight = 0; + numKeywaves = 24; + + addButtons (ControlButton::ButtonFunction::mode, 0.2f, 0.2f, + ControlButton::ButtonFunction::down, 0.6f, 0.2f, + ControlButton::ButtonFunction::up, 1.0f, 0.2f); + + addPortsSW (Block::ConnectionPort::DeviceEdge::west, 2); + addPortsNE (Block::ConnectionPort::DeviceEdge::north, 4); + addPortsNE (Block::ConnectionPort::DeviceEdge::east, 2); + + hasTouchSurface = true; + programAndHeapSize = BlocksProtocol::padBlockProgramAndHeapSize; + + defaultConfig.add ({ mode, 0, 0, 3, false, + "Color Mode", ConfigType::options, + { "Multi-color Mode", + "Single Color Mode", + "Piano Mode", + "Night Mode" + }, + BlockConfigManager::playGroup }); + + defaultConfig.add ({ zTrackingMode, 0, 0, 1, false, + "Pressure Tracking Mode", ConfigType::options, + { "Poly Aftertouch", "Channel Pressure" }, + BlockConfigManager::playGroup }); + } + //============================================================================== void addStatusLED (const char* name, float x, float y) { diff --git a/modules/juce_blocks_basics/protocol/juce_BlocksProtocolDefinitions.h b/modules/juce_blocks_basics/protocol/juce_BlocksProtocolDefinitions.h index b2399d50..7a80fe5a 100644 --- a/modules/juce_blocks_basics/protocol/juce_BlocksProtocolDefinitions.h +++ b/modules/juce_blocks_basics/protocol/juce_BlocksProtocolDefinitions.h @@ -185,7 +185,7 @@ struct BlockSerialNumber : public BlockStringData<16> if (c == 0) return false; - return isAnyControlBlock() || isPadBlock() || isSeaboardBlock(); + return isAnyControlBlock() || isPadBlock() || isSeaboardBlock() || isLumiKeysBlock(); } bool isPadBlock() const noexcept { return hasPrefix ("LPB") || hasPrefix ("LPM"); } @@ -194,6 +194,7 @@ struct BlockSerialNumber : public BlockStringData<16> bool isDevCtrlBlock() const noexcept { return hasPrefix ("DCB"); } bool isTouchBlock() const noexcept { return hasPrefix ("TCB"); } bool isSeaboardBlock() const noexcept { return hasPrefix ("SBB"); } + bool isLumiKeysBlock() const noexcept { return hasPrefix ("LKB"); } bool isAnyControlBlock() const noexcept { return isLiveBlock() || isLoopBlock() || isDevCtrlBlock() || isTouchBlock(); } diff --git a/modules/juce_blocks_basics/topology/internal/juce_BlockImplementation.cpp b/modules/juce_blocks_basics/topology/internal/juce_BlockImplementation.cpp index 6d3a7fbd..45dc0c07 100644 --- a/modules/juce_blocks_basics/topology/internal/juce_BlockImplementation.cpp +++ b/modules/juce_blocks_basics/topology/internal/juce_BlockImplementation.cpp @@ -40,7 +40,8 @@ public: deviceInfo.name.asString()), modelData (deviceInfo.serial), remoteHeap (modelData.programAndHeapSize), - detector (&detectorToUse) + detector (&detectorToUse), + config (modelData.defaultConfig) { markReconnected (deviceInfo); @@ -219,10 +220,7 @@ public: bool sendMessageToDevice (const PacketBuilder& builder) { if (detector != nullptr) - { - lastMessageSendTime = Time::getCurrentTime(); return detector->sendMessageToDevice (uid, builder); - } return false; } @@ -456,7 +454,7 @@ public: void pingFromDevice() { - lastMessageReceiveTime = Time::getCurrentTime(); + lastPingReceiveTime = Time::getCurrentTime(); } MIDIDeviceConnection* getDeviceConnection() @@ -510,8 +508,11 @@ public: remoteHeap.sendChanges (*this, false); - if (lastMessageSendTime < Time::getCurrentTime() - getPingInterval()) + if (lastPingSendTime < Time::getCurrentTime() - getPingInterval()) + { + lastPingSendTime = Time::getCurrentTime(); sendCommandMessage (BlocksProtocol::ping); + } } RelativeTime getPingInterval() @@ -653,7 +654,7 @@ public: RemoteHeapType remoteHeap; WeakReference detector; - Time lastMessageSendTime, lastMessageReceiveTime; + Time lastPingSendTime, lastPingReceiveTime; BlockConfigManager config; std::function configChangedCallback; diff --git a/modules/juce_blocks_basics/topology/internal/juce_DepreciatedVersionReader.cpp b/modules/juce_blocks_basics/topology/internal/juce_DepreciatedVersionReader.cpp index c871d092..f237ee19 100644 --- a/modules/juce_blocks_basics/topology/internal/juce_DepreciatedVersionReader.cpp +++ b/modules/juce_blocks_basics/topology/internal/juce_DepreciatedVersionReader.cpp @@ -25,7 +25,7 @@ namespace juce /** Firmware below 0.3.0 does not report its version over the Blocks API. - This class can make requests and process responses to retreive the master Block version. + This class can make requests and process responses to retrieve the master Block version. */ class DepreciatedVersionReader : private MIDIDeviceConnection::Listener, private Timer diff --git a/modules/juce_blocks_basics/topology/internal/juce_Detector.cpp b/modules/juce_blocks_basics/topology/internal/juce_Detector.cpp index 09bffab6..9a0df53d 100644 --- a/modules/juce_blocks_basics/topology/internal/juce_Detector.cpp +++ b/modules/juce_blocks_basics/topology/internal/juce_Detector.cpp @@ -537,6 +537,24 @@ private: return 1; } } + else if (block->getType() == Block::lumiKeysBlock) + { + if (edge == Block::ConnectionPort::DeviceEdge::north) + { + switch (index) + { + case 0 : return 0; + case 1 : return 2; + case 2 : return 3; + case 3 : return 5; + default : jassertfalse; + } + } + else if (edge == Block::ConnectionPort::DeviceEdge::south) + { + jassertfalse; + } + } if (edge == Block::ConnectionPort::DeviceEdge::south) return block->getWidth() - (index + 1); diff --git a/modules/juce_blocks_basics/topology/internal/juce_MIDIDeviceDetector.cpp b/modules/juce_blocks_basics/topology/internal/juce_MIDIDeviceDetector.cpp index 43a84538..725afb54 100644 --- a/modules/juce_blocks_basics/topology/internal/juce_MIDIDeviceDetector.cpp +++ b/modules/juce_blocks_basics/topology/internal/juce_MIDIDeviceDetector.cpp @@ -149,8 +149,8 @@ private: bool lockedFromOutside = true; /** For backwards compatibility, the block interprocess lock has to use the midi input name. - The below is necceccary because blocks of the same type might duplicate a port name, so - must share an interporcess lock. + The below is necessary because blocks of the same type might duplicate a port name, so + must share an interprocess lock. */ std::shared_ptr createMidiPortLock (const String& midiInName, const String& midiOutName) { diff --git a/modules/juce_blocks_basics/topology/juce_BlockGraph.h b/modules/juce_blocks_basics/topology/juce_BlockGraph.h index 7509c029..989ec4e2 100644 --- a/modules/juce_blocks_basics/topology/juce_BlockGraph.h +++ b/modules/juce_blocks_basics/topology/juce_BlockGraph.h @@ -27,11 +27,13 @@ namespace juce /** Represents traversal paths from master blocks and any connected blocks. + + @tags{Blocks} */ class BlockGraph { public: - /** Creates a BlockGraph object from a BlockTopology with an optional filter fucntion. This + /** Creates a BlockGraph object from a BlockTopology with an optional filter function. This will build a block graph of traversal paths for each master. */ BlockGraph (const BlockTopology topology, std::function filter = nullptr); diff --git a/modules/juce_blocks_basics/topology/juce_Topology.h b/modules/juce_blocks_basics/topology/juce_Topology.h index d2ab65ef..46c122ac 100644 --- a/modules/juce_blocks_basics/topology/juce_Topology.h +++ b/modules/juce_blocks_basics/topology/juce_Topology.h @@ -23,7 +23,7 @@ namespace juce { -/** Describes a phyiscal connection between two ports of two block devices. +/** Describes a physical connection between two ports of two block devices. @tags{Blocks} */ diff --git a/modules/juce_box2d/juce_box2d.h b/modules/juce_box2d/juce_box2d.h index 5080c705..f4310a6d 100644 --- a/modules/juce_box2d/juce_box2d.h +++ b/modules/juce_box2d/juce_box2d.h @@ -24,6 +24,7 @@ ============================================================================== */ + /******************************************************************************* The block below describes the properties of this module, and is read by the Projucer to automatically generate project code that uses it. @@ -33,15 +34,15 @@ BEGIN_JUCE_MODULE_DECLARATION - ID: juce_box2d - vendor: juce - version: 5.4.5 - name: JUCE wrapper for the Box2D physics engine - description: The Box2D physics engine and some utility classes. - website: http://www.juce.com/juce - license: GPL/Commercial + ID: juce_box2d + vendor: juce + version: 5.4.6 + name: JUCE wrapper for the Box2D physics engine + description: The Box2D physics engine and some utility classes. + website: http://www.juce.com/juce + license: GPL/Commercial - dependencies: juce_graphics + dependencies: juce_graphics END_JUCE_MODULE_DECLARATION diff --git a/modules/juce_core/containers/juce_Array.h b/modules/juce_core/containers/juce_Array.h index 3b516751..a2a37186 100644 --- a/modules/juce_core/containers/juce_Array.h +++ b/modules/juce_core/containers/juce_Array.h @@ -30,7 +30,7 @@ namespace juce Examples of arrays are: Array, Array or Array The Array class can be used to hold simple, non-polymorphic objects as well as primitive types - to - do so, the class must fulfil these requirements: + do so, the class must fulfill these requirements: - it must have a copy constructor and assignment operator - it must be able to be relocated in memory by a memcpy without this causing any problems - so objects whose functionality relies on external pointers or references to themselves can not be used. diff --git a/modules/juce_core/containers/juce_ArrayBase.cpp b/modules/juce_core/containers/juce_ArrayBase.cpp index 6893e063..7a79da62 100644 --- a/modules/juce_core/containers/juce_ArrayBase.cpp +++ b/modules/juce_core/containers/juce_ArrayBase.cpp @@ -304,7 +304,7 @@ public: checkEqual (copyableContainer, noncopyableContainer, referenceContainer); } - beginTest ("add array from initilizer list"); + beginTest ("add array from initializer_list"); { std::vector referenceContainer; ArrayBase copyableContainer; diff --git a/modules/juce_core/containers/juce_DynamicObject.h b/modules/juce_core/containers/juce_DynamicObject.h index 9085e090..aed21086 100644 --- a/modules/juce_core/containers/juce_DynamicObject.h +++ b/modules/juce_core/containers/juce_DynamicObject.h @@ -78,7 +78,7 @@ public: call, then it invokes it. This method is virtual to allow more dynamic invocation to used for objects - where the methods may not already be set as properies. + where the methods may not already be set as properties. */ virtual var invokeMethod (Identifier methodName, const var::NativeFunctionArgs& args); diff --git a/modules/juce_core/containers/juce_PropertySet.h b/modules/juce_core/containers/juce_PropertySet.h index de83ba21..b14cabf5 100644 --- a/modules/juce_core/containers/juce_PropertySet.h +++ b/modules/juce_core/containers/juce_PropertySet.h @@ -143,7 +143,7 @@ public: */ void removeValue (StringRef keyName); - /** Returns true if the properies include the given key. */ + /** Returns true if the properties include the given key. */ bool containsKey (StringRef keyName) const noexcept; /** Removes all values. */ @@ -190,7 +190,7 @@ public: PropertySet* getFallbackPropertySet() const noexcept { return fallbackProperties; } protected: - /** Subclasses can override this to be told when one of the properies has been changed. */ + /** Subclasses can override this to be told when one of the properties has been changed. */ virtual void propertyChanged(); private: diff --git a/modules/juce_core/containers/juce_Variant.h b/modules/juce_core/containers/juce_Variant.h index e115d770..2596576c 100644 --- a/modules/juce_core/containers/juce_Variant.h +++ b/modules/juce_core/containers/juce_Variant.h @@ -302,7 +302,7 @@ private: int64 int64Value; bool boolValue; double doubleValue; - char stringValue [sizeof (String)]; + char stringValue[sizeof (String)]; ReferenceCountedObject* objectValue; MemoryBlock* binaryValue; NativeFunction* methodValue; @@ -319,6 +319,8 @@ private: // This is needed to prevent the wrong constructor/operator being called var (const ReferenceCountedObject*) = delete; var& operator= (const ReferenceCountedObject*) = delete; + var (const void*) = delete; + var& operator= (const void*) = delete; }; /** Compares the values of two var objects, using the var::equals() comparison. */ diff --git a/modules/juce_core/files/juce_File.cpp b/modules/juce_core/files/juce_File.cpp index e07968b1..7041ecd8 100644 --- a/modules/juce_core/files/juce_File.cpp +++ b/modules/juce_core/files/juce_File.cpp @@ -104,6 +104,26 @@ static String removeEllipsis (const String& path) return path; } +static String normaliseSeparators (const String& path) +{ + auto normalisedPath = path; + + String separator (File::getSeparatorString()); + String doubleSeparator (separator + separator); + + auto uncPath = normalisedPath.startsWith (doubleSeparator) + && ! normalisedPath.fromFirstOccurrenceOf (doubleSeparator, false, false).startsWith (separator); + + if (uncPath) + normalisedPath = normalisedPath.fromFirstOccurrenceOf (doubleSeparator, false, false); + + while (normalisedPath.contains (doubleSeparator)) + normalisedPath = normalisedPath.replace (doubleSeparator, separator); + + return uncPath ? doubleSeparator + normalisedPath + : normalisedPath; +} + bool File::isRoot() const { return fullPath.isNotEmpty() && *this == getParentDirectory(); @@ -114,9 +134,9 @@ String File::parseAbsolutePath (const String& p) if (p.isEmpty()) return {}; -#if JUCE_WINDOWS + #if JUCE_WINDOWS // Windows.. - auto path = removeEllipsis (p.replaceCharacter ('/', '\\')); + auto path = normaliseSeparators (removeEllipsis (p.replaceCharacter ('/', '\\'))); if (path.startsWithChar (getSeparatorChar())) { @@ -147,7 +167,7 @@ String File::parseAbsolutePath (const String& p) return File::getCurrentWorkingDirectory().getChildFile (path).getFullPathName(); } -#else + #else // Mac or Linux.. // Yes, I know it's legal for a unix pathname to contain a backslash, but this assertion is here @@ -155,7 +175,7 @@ String File::parseAbsolutePath (const String& p) // If that's why you've ended up here, use File::getChildFile() to build your paths instead. jassert ((! p.containsChar ('\\')) || (p.indexOfChar ('/') >= 0 && p.indexOfChar ('/') < p.indexOfChar ('\\'))); - auto path = removeEllipsis (p); + auto path = normaliseSeparators (removeEllipsis (p)); if (path.startsWithChar ('~')) { @@ -196,7 +216,7 @@ String File::parseAbsolutePath (const String& p) return File::getCurrentWorkingDirectory().getChildFile (path).getFullPathName(); } -#endif + #endif while (path.endsWithChar (getSeparatorChar()) && path != getSeparatorString()) // careful not to turn a single "/" into an empty string. path = path.dropLastCharacters (1); diff --git a/modules/juce_core/javascript/juce_Javascript.cpp b/modules/juce_core/javascript/juce_Javascript.cpp index 6cfcc909..4a92686c 100644 --- a/modules/juce_core/javascript/juce_Javascript.cpp +++ b/modules/juce_core/javascript/juce_Javascript.cpp @@ -816,7 +816,8 @@ struct JavascriptEngine::RootObject : public DynamicObject for (int i = 0; i < values.size(); ++i) a.add (values.getUnchecked(i)->getResult (s)); - return a; + // std::move() needed here for older compilers + return std::move (a); } OwnedArray values; @@ -1625,7 +1626,8 @@ struct JavascriptEngine::RootObject : public DynamicObject for (int i = 2; i < a.numArguments; ++i) array->insert (start++, get (a, i)); - return itemsRemoved; + // std::move() needed here for older compilers + return std::move (itemsRemoved); } return var::undefined(); diff --git a/modules/juce_core/juce_core.cpp b/modules/juce_core/juce_core.cpp old mode 100755 new mode 100644 index a7d26cd6..1c58ba77 --- a/modules/juce_core/juce_core.cpp +++ b/modules/juce_core/juce_core.cpp @@ -110,10 +110,6 @@ #include #endif -#if JUCE_BELA - #include -#endif - #undef check //============================================================================== @@ -145,7 +141,6 @@ #include "misc/juce_RuntimePermissions.cpp" #include "misc/juce_Result.cpp" #include "misc/juce_Uuid.cpp" -#include "misc/juce_StdFunctionCompat.cpp" #include "misc/juce_ConsoleApplication.cpp" #include "network/juce_MACAddress.cpp" #include "network/juce_NamedPipe.cpp" @@ -239,6 +234,7 @@ #include "threads/juce_ChildProcess.cpp" #include "threads/juce_HighResolutionTimer.cpp" +#include "threads/juce_WaitableEvent.cpp" #include "network/juce_URL.cpp" #include "network/juce_WebInputStream.cpp" #include "streams/juce_URLInputSource.cpp" diff --git a/modules/juce_core/juce_core.h b/modules/juce_core/juce_core.h index 9cd41469..3a88ff18 100644 --- a/modules/juce_core/juce_core.h +++ b/modules/juce_core/juce_core.h @@ -30,19 +30,19 @@ BEGIN_JUCE_MODULE_DECLARATION - ID: juce_core - vendor: juce - version: 5.4.5 - name: JUCE core classes - description: The essential set of basic JUCE classes, as required by all the other JUCE modules. Includes text, container, memory, threading and i/o functionality. - website: http://www.juce.com/juce - license: ISC + ID: juce_core + vendor: juce + version: 5.4.6 + name: JUCE core classes + description: The essential set of basic JUCE classes, as required by all the other JUCE modules. Includes text, container, memory, threading and i/o functionality. + website: http://www.juce.com/juce + license: ISC dependencies: - OSXFrameworks: Cocoa IOKit - iOSFrameworks: Foundation - linuxLibs: rt dl pthread - mingwLibs: uuid wsock32 wininet version ole32 ws2_32 oleaut32 imm32 comdlg32 shlwapi rpcrt4 winmm + OSXFrameworks: Cocoa IOKit + iOSFrameworks: Foundation + linuxLibs: rt dl pthread + mingwLibs: uuid wsock32 wininet version ole32 ws2_32 oleaut32 imm32 comdlg32 shlwapi rpcrt4 winmm END_JUCE_MODULE_DECLARATION @@ -142,7 +142,7 @@ /** Config: JUCE_LOAD_CURL_SYMBOLS_LAZILY If enabled, JUCE will load libcurl lazily when required (for example, when WebInputStream - is used). Enabling this flag may also help with library dependency erros as linking + is used). Enabling this flag may also help with library dependency errors as linking libcurl at compile-time may instruct the linker to hard depend on a specific version of libcurl. It's also useful if you want to limit the amount of JUCE dependencies and you are not using WebInputStream or the URL classes. diff --git a/modules/juce_core/logging/juce_FileLogger.h b/modules/juce_core/logging/juce_FileLogger.h index b6b10745..50e5c874 100644 --- a/modules/juce_core/logging/juce_FileLogger.h +++ b/modules/juce_core/logging/juce_FileLogger.h @@ -83,7 +83,7 @@ public: The filename used is based on the root and suffix strings provided, along with a time and date string, meaning that a new, empty log file will be always be created - rather than appending to an exising one. + rather than appending to an existing one. The method might return nullptr if the file can't be created for some reason. diff --git a/modules/juce_core/memory/juce_ReferenceCountedObject.h b/modules/juce_core/memory/juce_ReferenceCountedObject.h index 617d2d09..575687d8 100644 --- a/modules/juce_core/memory/juce_ReferenceCountedObject.h +++ b/modules/juce_core/memory/juce_ReferenceCountedObject.h @@ -49,9 +49,14 @@ namespace juce Once a new ReferenceCountedObject has been assigned to a pointer, be careful not to delete the object manually. - This class uses an Atomic value to hold the reference count, so that - the pointers can be passed between threads safely. For a faster but non-thread-safe - version, use SingleThreadedReferenceCountedObject instead. + This class uses an Atomic value to hold the reference count, so + the reference count can be updated on multiple threads. Note that + whilst it's thread-safe to create and delete a ReferenceCountedObjectPtr + to a ReferenceCountedObject shared between threads, it's not thread-safe + to modify or swap the ReferenceCountedObject. + + For a faster but non-thread-safe version, use SingleThreadedReferenceCountedObject + instead. @see ReferenceCountedObjectPtr, ReferenceCountedArray, SingleThreadedReferenceCountedObject diff --git a/modules/juce_core/misc/juce_ConsoleApplication.cpp b/modules/juce_core/misc/juce_ConsoleApplication.cpp index bf3bf5c7..da5548b4 100644 --- a/modules/juce_core/misc/juce_ConsoleApplication.cpp +++ b/modules/juce_core/misc/juce_ConsoleApplication.cpp @@ -308,7 +308,7 @@ int ConsoleApplication::invokeCatchingFailures (std::function&& f) } catch (const ConsoleAppFailureCode& error) { - std::cout << error.errorMessage << std::endl; + std::cerr << error.errorMessage << std::endl; returnCode = error.returnCode; } diff --git a/modules/juce_core/misc/juce_ConsoleApplication.h b/modules/juce_core/misc/juce_ConsoleApplication.h index bc46c514..a6440177 100644 --- a/modules/juce_core/misc/juce_ConsoleApplication.h +++ b/modules/juce_core/misc/juce_ConsoleApplication.h @@ -32,6 +32,8 @@ namespace juce main() function to parse. @see ConsoleApplication + + @tags{Core} */ struct ArgumentList { @@ -50,6 +52,8 @@ struct ArgumentList //============================================================================== /** One of the arguments in an ArgumentList. + + @tags{Core} */ struct Argument { @@ -226,13 +230,18 @@ struct ArgumentList @endcode @see ArgumentList + + @tags{Core} */ struct ConsoleApplication { //============================================================================== /** Represents a command that can be executed if its command-line arguments are matched. + @see ConsoleApplication::addCommand(), ConsoleApplication::findAndRunCommand() + + @tags{Core} */ struct Command { diff --git a/modules/juce_core/misc/juce_StdFunctionCompat.cpp b/modules/juce_core/misc/juce_StdFunctionCompat.cpp deleted file mode 100644 index ece1e5ec..00000000 --- a/modules/juce_core/misc/juce_StdFunctionCompat.cpp +++ /dev/null @@ -1,284 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - Permission is granted to use this software under the terms of the ISC license - http://www.isc.org/downloads/software-support-policy/isc-license/ - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH REGARD - TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND - FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, - OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF - USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER - TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE - OF THIS SOFTWARE. - - ----------------------------------------------------------------------------- - - To release a closed-source product which uses other parts of JUCE not - licensed under the ISC terms, commercial licenses are available: visit - www.juce.com for more information. - - ============================================================================== -*/ - -namespace juce -{ - -#if JUCE_UNIT_TESTS - -namespace FunctionTestsHelpers -{ - static void incrementArgument (int& x) { x++; } - static double multiply (double x, double a) noexcept { return a * x; } - - struct BigData - { - BigData() - { - for (auto i = 0; i < bigDataSize; ++i) - content[i] = i + 1; - } - - int sum() const - { - int result = 0; - for (auto i = 0; i < bigDataSize; ++i) - result += content[i]; - - return result; - } - - static const int bigDataSize = 32, - bigDataSum = bigDataSize * (bigDataSize + 1) / 2; - int content[bigDataSize]; - }; - - struct FunctionObject - { - FunctionObject() = default; - - FunctionObject (const FunctionObject& other) - { - bigData.reset (new BigData (*other.bigData)); - } - - int operator()(int i) const { return bigData->sum() + i; } - - std::unique_ptr bigData { new BigData() }; - - JUCE_LEAK_DETECTOR (FunctionObject) - }; - - struct BigFunctionObject - { - BigFunctionObject() = default; - - BigFunctionObject (const BigFunctionObject& other) - { - bigData.reset (new BigData (*other.bigData)); - } - - int operator()(int i) const { return bigData->sum() + i; } - - std::unique_ptr bigData { new BigData() }; - - int stackUsage[32]; - - JUCE_LEAK_DETECTOR (BigFunctionObject) - }; -} - -class FunctionTests : public UnitTest -{ -public: - FunctionTests() - : UnitTest ("Function", UnitTestCategories::function) - {} - - void runTest() override - { - FunctionTestsHelpers::BigData bigData; - - { - beginTest ("Functions"); - - std::function f1 (FunctionTestsHelpers::incrementArgument); - - auto x = 0; - f1 (x); - expectEquals (x, 1); - - std::function f2 (FunctionTestsHelpers::multiply); - expectEquals (6.0, f2 (2.0, 3.0)); - } - - { - beginTest ("Function objects"); - - std::function f1 = FunctionTestsHelpers::FunctionObject(); - expectEquals (f1 (5), FunctionTestsHelpers::BigData::bigDataSum + 5); - - std::function f2 { FunctionTestsHelpers::BigFunctionObject() }; - expectEquals (f2 (5), FunctionTestsHelpers::BigData::bigDataSum + 5); - } - - { - beginTest ("Lambdas"); - - std::function fStack ([] { return 3; }); - expectEquals (fStack(), 3); - - std::function fHeap ([=] { return bigData.sum(); }); - expectEquals (fHeap(), FunctionTestsHelpers::BigData::bigDataSum); - } - - { - beginTest ("Boolean"); - - std::function f1; - - if (f1) - expect (false); - - std::function f2 ([]() { return 3; }); - - if (! f2) - expect (false); - } - - std::function fEmpty; - - std::function fStack ([] { return 3; }); - - std::function fHeap ([=] { return bigData.sum(); }); - - { - beginTest ("copy constructor"); - - std::function f1 (fStack); - expectEquals (f1(), 3); - - std::function f2 (fHeap); - expectEquals (f2(), FunctionTestsHelpers::BigData::bigDataSum); - - std::function f3 (fEmpty); - if (f3) - expect (false); - } - - { - beginTest ("assignment"); - - std::function f1; - f1 = fStack; - expectEquals (f1(), 3); - - std::function f2; - f2 = fHeap; - expectEquals (f2(), FunctionTestsHelpers::BigData::bigDataSum); - - f1 = fHeap; - expectEquals (f1(), FunctionTestsHelpers::BigData::bigDataSum); - - f2 = fStack; - expectEquals (f2(), 3); - - f1 = fEmpty; - if (f1) - expect (false); - } - - { - beginTest ("move constructor"); - - std::unique_ptr> fStackTmp (new std::function (fStack)); - std::function f1 (std::move (*fStackTmp)); - - fStackTmp.reset(); - expectEquals (f1(), 3); - - std::unique_ptr> fHeapTmp (new std::function (fHeap)); - std::function f2 (std::move (*fHeapTmp)); - if (*fHeapTmp) - expect (false); - - fHeapTmp.reset(); - expectEquals (f2(), FunctionTestsHelpers::BigData::bigDataSum); - - std::unique_ptr> fEmptyTmp (new std::function()); - std::function f3 (std::move (*fEmptyTmp)); - fEmptyTmp.reset(); - if (f3) - expect (false); - } - - { - beginTest ("move assignment"); - - std::function f1 (fHeap); - std::unique_ptr> fStackTmp (new std::function (fStack)); - f1 = std::move (*fStackTmp); - - fStackTmp.reset(); - expectEquals (f1(), 3); - - std::function f2 (fStack); - std::unique_ptr> fHeapTmp (new std::function (fHeap)); - f2 = std::move (*fHeapTmp); - if (*fHeapTmp) - expect (false); - - fHeapTmp.reset(); - expectEquals (f2(), FunctionTestsHelpers::BigData::bigDataSum); - - std::function f3 (fHeap); - std::unique_ptr> fEmptyTmp (new std::function()); - f3 = std::move (*fEmptyTmp); - fEmptyTmp.reset(); - if (f3) - expect (false); - } - - { - beginTest ("nullptr"); - - std::function f1 (nullptr); - if (f1) - expect (false); - - std::function f2 ([]() { return 11; }); - f2 = nullptr; - if (f2) - expect (false); - } - - { - beginTest ("Swap"); - - std::function f1; - std::function f2 (fStack); - f2.swap (f1); - expectEquals (f1(), 3); - if (f2) - expect (false); - - std::function f3 (fHeap); - f3.swap (f1); - expectEquals (f3(), 3); - expectEquals (f1(), FunctionTestsHelpers::BigData::bigDataSum); - } - } -}; - -static FunctionTests functionTests; - -#endif - -} // namespace juce diff --git a/modules/juce_core/misc/juce_StdFunctionCompat.h b/modules/juce_core/misc/juce_StdFunctionCompat.h deleted file mode 100644 index 94c65f4a..00000000 --- a/modules/juce_core/misc/juce_StdFunctionCompat.h +++ /dev/null @@ -1,206 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - Permission is granted to use this software under the terms of the ISC license - http://www.isc.org/downloads/software-support-policy/isc-license/ - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH REGARD - TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND - FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, - OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF - USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER - TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE - OF THIS SOFTWARE. - - ----------------------------------------------------------------------------- - - To release a closed-source product which uses other parts of JUCE not - licensed under the ISC terms, commercial licenses are available: visit - www.juce.com for more information. - - ============================================================================== -*/ - -namespace std -{ - /** - This class provides an alternative to std::function that is compatible - with OS X 10.6 and earlier. This will only be used in OS X versions 10.6 - and earlier and the Projucer live build. - - @tags{Core} - */ - template - class function; - - #ifndef DOXYGEN - template - class function - { - public: - /** Creates an empty function. */ - function() noexcept {} - - /** Creates an empty function. */ - function (decltype (nullptr)) noexcept {} - - /** Creates a function targeting the provided Functor. */ - template - function (Functor f) - { - functorHolderHelper = getFunctorStorage (sizeof (FunctorHolder)); - new (functorHolderHelper) FunctorHolder (f); - } - - /** Copy constructor. */ - function (function const& other) - { - copy (other); - } - - /** Move constructor */ - function (function&& other) - { - move (other); - } - - /** Destructor. */ - ~function() - { - release(); - } - - /** Replaces the contents of this function with the contents of another. */ - function& operator= (function const& other) - { - release(); - copy (other); - - return *this; - } - - /** Moves the contents of another function into this one. */ - function& operator= (function&& other) - { - release(); - move (other); - - return *this; - } - - /** Allows conditional expressions to test if this function is empty. */ - explicit operator bool() const noexcept - { - return functorHolderHelper != nullptr; - } - - /** Swaps the contents of this function with another. After this operation the - two functions will be pointing at each other's targets. */ - void swap (function& other) - { - function tmp (*this); - *this = other; - other = tmp; - } - - /** Invokes the target of this function. */ - Result operator() (Arguments... args) const - { - return (*functorHolderHelper) (std::forward (args)...); - } - - bool operator== (decltype (nullptr)) const noexcept { return (functorHolderHelper == nullptr); } - bool operator!= (decltype (nullptr)) const noexcept { return (functorHolderHelper != nullptr); } - - private: - //============================================================================== - template - struct FunctorHolderBase - { - virtual ~FunctorHolderBase() {} - virtual int getSize() const noexcept = 0; - virtual void copy (void*) const = 0; - virtual ReturnType operator()(Args...) = 0; - }; - - template - struct FunctorHolder : FunctorHolderBase - { - FunctorHolder (Functor func) : f (func) {} - - int getSize() const noexcept override final - { - return sizeof (*this); - } - - void copy (void* destination) const override final - { - new (destination) FunctorHolder (f); - } - - ReturnType operator()(Args... args) override final - { - return f (std::forward (args)...); - } - - Functor f; - }; - - FunctorHolderBase* getFunctorStorage (int size) - { - return reinterpret_cast*> - (size > functorHolderStackSize ? new char [static_cast (size)] - : &(stackFunctorStorage[0])); - } - - void copy (function const& other) - { - if (other.functorHolderHelper != nullptr) - { - functorHolderHelper = getFunctorStorage (other.functorHolderHelper->getSize()); - other.functorHolderHelper->copy (functorHolderHelper); - } - } - - void move (function& other) - { - if (other.functorHolderHelper != nullptr) - { - if (other.functorHolderHelper->getSize() > functorHolderStackSize) - { - functorHolderHelper = other.functorHolderHelper; - } - else - { - std::copy (other.stackFunctorStorage, other.stackFunctorStorage + functorHolderStackSize, - stackFunctorStorage); - functorHolderHelper = reinterpret_cast*> (&(stackFunctorStorage[0])); - } - - other.functorHolderHelper = nullptr; - } - } - - void release() - { - if (functorHolderHelper != nullptr) - { - functorHolderHelper->~FunctorHolderBase(); - functorHolderHelper = nullptr; - } - } - - static const int functorHolderStackSize = 24; - char stackFunctorStorage[functorHolderStackSize]; - - FunctorHolderBase* functorHolderHelper = nullptr; - }; - #endif -} diff --git a/modules/juce_core/native/juce_android_Network.cpp b/modules/juce_core/native/juce_android_Network.cpp index 83e8522d..8808d170 100644 --- a/modules/juce_core/native/juce_android_Network.cpp +++ b/modules/juce_core/native/juce_android_Network.cpp @@ -213,6 +213,62 @@ DECLARE_JNI_CLASS_WITH_BYTECODE (HTTPStream, "com/roli/juce/JuceHTTPStream", 16, DECLARE_JNI_CLASS (AndroidInputStream, "java/io/InputStream") #undef JNI_CLASS_MEMBERS +//============================================================================== +#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \ + METHOD (acquire, "acquire", "()V") \ + METHOD (release, "release", "()V") \ + +DECLARE_JNI_CLASS (AndroidMulticastLock, "android/net/wifi/WifiManager$MulticastLock") +#undef JNI_CLASS_MEMBERS + +#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \ + METHOD (createMulticastLock, "createMulticastLock", "(Ljava/lang/String;)Landroid/net/wifi/WifiManager$MulticastLock;") \ + +DECLARE_JNI_CLASS (AndroidWifiManager, "android/net/wifi/WifiManager") +#undef JNI_CLASS_MEMBERS + +static LocalRef getMulticastLock() +{ + static LocalRef multicastLock; + static bool hasChecked = false; + + if (! hasChecked) + { + hasChecked = true; + + auto* env = getEnv(); + + LocalRef wifiManager (env->CallObjectMethod (getAppContext().get(), + AndroidContext.getSystemService, + javaString ("wifi").get())); + + if (wifiManager != nullptr) + { + multicastLock = LocalRef (env->CallObjectMethod (wifiManager.get(), + AndroidWifiManager.createMulticastLock, + javaString ("JUCE_MulticastLock").get())); + } + } + + return multicastLock; +} + +JUCE_API void JUCE_CALLTYPE acquireMulticastLock() +{ + auto multicastLock = getMulticastLock(); + + if (multicastLock != nullptr) + getEnv()->CallVoidMethod (multicastLock.get(), AndroidMulticastLock.acquire); +} + +JUCE_API void JUCE_CALLTYPE releaseMulticastLock() +{ + auto multicastLock = getMulticastLock(); + + if (multicastLock != nullptr) + getEnv()->CallVoidMethod (multicastLock.get(), AndroidMulticastLock.release); +} + //============================================================================== void MACAddress::findAllAddresses (Array& /*result*/) { diff --git a/modules/juce_core/native/juce_linux_SystemStats.cpp b/modules/juce_core/native/juce_linux_SystemStats.cpp old mode 100755 new mode 100644 index 8d553e49..7ba2b5ef --- a/modules/juce_core/native/juce_linux_SystemStats.cpp +++ b/modules/juce_core/native/juce_linux_SystemStats.cpp @@ -20,6 +20,9 @@ ============================================================================== */ +#if JUCE_BELA +extern "C" int cobalt_thread_mode(); +#endif namespace juce { @@ -146,6 +149,8 @@ void CPUInformation::initialise() noexcept auto flags = getCpuInfo ("flags"); hasMMX = flags.contains ("mmx"); + hasFMA3 = flags.contains ("fma"); + hasFMA4 = flags.contains ("fma4"); hasSSE = flags.contains ("sse"); hasSSE2 = flags.contains ("sse2"); hasSSE3 = flags.contains ("sse3"); @@ -183,13 +188,18 @@ uint32 juce_millisecondsSinceStartup() noexcept int64 Time::getHighResolutionTicks() noexcept { + timespec t; + #if JUCE_BELA - return rt_timer_read() / 1000; + if (cobalt_thread_mode() == 0x200 /*XNRELAX*/) + clock_gettime (CLOCK_MONOTONIC, &t); + else + __wrap_clock_gettime (CLOCK_MONOTONIC, &t); #else - timespec t; clock_gettime (CLOCK_MONOTONIC, &t); - return (t.tv_sec * (int64) 1000000) + (t.tv_nsec / 1000); #endif + + return (t.tv_sec * (int64) 1000000) + (t.tv_nsec / 1000); } int64 Time::getHighResolutionTicksPerSecond() noexcept diff --git a/modules/juce_core/native/juce_mac_ClangBugWorkaround.h b/modules/juce_core/native/juce_mac_ClangBugWorkaround.h index 0eac3a31..eb02c171 100644 --- a/modules/juce_core/native/juce_mac_ClangBugWorkaround.h +++ b/modules/juce_core/native/juce_mac_ClangBugWorkaround.h @@ -20,10 +20,10 @@ ============================================================================== */ - -// This hack is a workaround for a bug (?) in Apple's 10.11 SDK headers -// which cause some configurations of Clang to throw out a spurious error.. #if JUCE_PROJUCER_LIVE_BUILD && (defined (__APPLE_CPP__) || defined(__APPLE_CC__)) + + // This hack is a workaround for a bug (?) in Apple's 10.11 SDK headers + // which cause some configurations of Clang to throw out a spurious error.. #include #undef CF_OPTIONS #define CF_OPTIONS(_type, _name) _type _name; enum @@ -33,93 +33,9 @@ #define _Nullable #define _Nonnull - // In later versions of libc++ these methods are defined in the functional header, - // which we don't compile in the live-build engine, so we'll define them here - #if defined (_LIBCPP_VERSION) && _LIBCPP_VERSION >= 7000 - #include - - namespace std { inline namespace __1 { - template - pair<_ForwardIterator1, _ForwardIterator1> _LIBCPP_CONSTEXPR_AFTER_CXX11 - __search(_ForwardIterator1 __first1, _ForwardIterator1 __last1, - _ForwardIterator2 __first2, _ForwardIterator2 __last2, _BinaryPredicate __pred, - forward_iterator_tag, forward_iterator_tag) - { - if (__first2 == __last2) - return make_pair(__first1, __first1); // Everything matches an empty sequence - while (true) - { - // Find first element in sequence 1 that matchs *__first2, with a mininum of loop checks - while (true) - { - if (__first1 == __last1) // return __last1 if no element matches *__first2 - return make_pair(__last1, __last1); - if (__pred(*__first1, *__first2)) - break; - ++__first1; - } - // *__first1 matches *__first2, now match elements after here - _ForwardIterator1 __m1 = __first1; - _ForwardIterator2 __m2 = __first2; - while (true) - { - if (++__m2 == __last2) // If pattern exhausted, __first1 is the answer (works for 1 element pattern) - return make_pair(__first1, __m1); - if (++__m1 == __last1) // Otherwise if source exhaused, pattern not found - return make_pair(__last1, __last1); - if (!__pred(*__m1, *__m2)) // if there is a mismatch, restart with a new __first1 - { - ++__first1; - break; - } // else there is a match, check next elements - } - } - } - - template - _LIBCPP_CONSTEXPR_AFTER_CXX11 - pair<_RandomAccessIterator1, _RandomAccessIterator1> - __search(_RandomAccessIterator1 __first1, _RandomAccessIterator1 __last1, - _RandomAccessIterator2 __first2, _RandomAccessIterator2 __last2, _BinaryPredicate __pred, - random_access_iterator_tag, random_access_iterator_tag) - { - typedef typename iterator_traits<_RandomAccessIterator1>::difference_type _D1; - typedef typename iterator_traits<_RandomAccessIterator2>::difference_type _D2; - // Take advantage of knowing source and pattern lengths. Stop short when source is smaller than pattern - const _D2 __len2 = __last2 - __first2; - if (__len2 == 0) - return make_pair(__first1, __first1); - const _D1 __len1 = __last1 - __first1; - if (__len1 < __len2) - return make_pair(__last1, __last1); - const _RandomAccessIterator1 __s = __last1 - (__len2 - 1); // Start of pattern match can't go beyond here - - while (true) - { - while (true) - { - if (__first1 == __s) - return make_pair(__last1, __last1); - if (__pred(*__first1, *__first2)) - break; - ++__first1; - } - - _RandomAccessIterator1 __m1 = __first1; - _RandomAccessIterator2 __m2 = __first2; - while (true) - { - if (++__m2 == __last2) - return make_pair(__first1, __first1 + __len2); - ++__m1; // no need to check range on __m1 because __s guarantees we have enough source - if (!__pred(*__m1, *__m2)) - { - ++__first1; - break; - } - } - } - } - } } - #endif + // A workaround for compiling the 10.15 headers with an older compiler version + #undef API_UNAVAILABLE_BEGIN + #define API_UNAVAILABLE_BEGIN(...) + #undef API_UNAVAILABLE_END + #define API_UNAVAILABLE_END #endif diff --git a/modules/juce_core/native/juce_mac_Files.mm b/modules/juce_core/native/juce_mac_Files.mm index 1446ca1f..53031211 100644 --- a/modules/juce_core/native/juce_mac_Files.mm +++ b/modules/juce_core/native/juce_mac_Files.mm @@ -415,10 +415,7 @@ bool JUCE_CALLTYPE Process::openDocument (const String& fileName, const String& NSWorkspace* workspace = [NSWorkspace sharedWorkspace]; if (parameters.isEmpty()) - // NB: the length check here is because of strange failures involving long filenames, - // probably due to filesystem name length limitations.. - return (fileName.length() < 1024 && [workspace openFile: juceStringToNS (fileName)]) - || [workspace openURL: filenameAsURL]; + return [workspace openURL: filenameAsURL]; const File file (fileName); diff --git a/modules/juce_core/native/juce_mac_SystemStats.mm b/modules/juce_core/native/juce_mac_SystemStats.mm index 885a45d8..58888608 100644 --- a/modules/juce_core/native/juce_mac_SystemStats.mm +++ b/modules/juce_core/native/juce_mac_SystemStats.mm @@ -81,10 +81,14 @@ void CPUInformation::initialise() noexcept has3DNow = (b & (1u << 31)) != 0; hasSSE3 = (c & (1u << 0)) != 0; hasSSSE3 = (c & (1u << 9)) != 0; + hasFMA3 = (c & (1u << 12)) != 0; hasSSE41 = (c & (1u << 19)) != 0; hasSSE42 = (c & (1u << 20)) != 0; hasAVX = (c & (1u << 28)) != 0; + SystemStatsHelpers::doCPUID (a, b, c, d, 0x80000001); + hasFMA4 = (c & (1u << 16)) != 0; + SystemStatsHelpers::doCPUID (a, b, c, d, 7); hasAVX2 = (b & (1u << 5)) != 0; hasAVX512F = (b & (1u << 16)) != 0; diff --git a/modules/juce_core/native/juce_mac_Threads.mm b/modules/juce_core/native/juce_mac_Threads.mm index 36943c77..bd8084cf 100644 --- a/modules/juce_core/native/juce_mac_Threads.mm +++ b/modules/juce_core/native/juce_mac_Threads.mm @@ -65,20 +65,10 @@ JUCE_API void JUCE_CALLTYPE Process::hide() } } -JUCE_API void JUCE_CALLTYPE Process::raisePrivilege() -{ - jassertfalse; -} +JUCE_API void JUCE_CALLTYPE Process::raisePrivilege() {} +JUCE_API void JUCE_CALLTYPE Process::lowerPrivilege() {} -JUCE_API void JUCE_CALLTYPE Process::lowerPrivilege() -{ - jassertfalse; -} - -JUCE_API void JUCE_CALLTYPE Process::setPriority (ProcessPriority) -{ - // xxx -} +JUCE_API void JUCE_CALLTYPE Process::setPriority (ProcessPriority) {} //============================================================================== JUCE_API bool JUCE_CALLTYPE juce_isRunningUnderDebugger() noexcept diff --git a/modules/juce_core/native/juce_posix_SharedCode.h b/modules/juce_core/native/juce_posix_SharedCode.h index e035a107..5d30962c 100644 --- a/modules/juce_core/native/juce_posix_SharedCode.h +++ b/modules/juce_core/native/juce_posix_SharedCode.h @@ -40,95 +40,6 @@ void CriticalSection::enter() const noexcept { pthread_mutex_lock (&lock) bool CriticalSection::tryEnter() const noexcept { return pthread_mutex_trylock (&lock) == 0; } void CriticalSection::exit() const noexcept { pthread_mutex_unlock (&lock); } -//============================================================================== -WaitableEvent::WaitableEvent (bool useManualReset) noexcept - : triggered (false), manualReset (useManualReset) -{ - pthread_cond_init (&condition, {}); - - pthread_mutexattr_t atts; - pthread_mutexattr_init (&atts); - #if ! JUCE_ANDROID - pthread_mutexattr_setprotocol (&atts, PTHREAD_PRIO_INHERIT); - #endif - pthread_mutex_init (&mutex, &atts); - pthread_mutexattr_destroy (&atts); -} - -WaitableEvent::~WaitableEvent() noexcept -{ - pthread_cond_destroy (&condition); - pthread_mutex_destroy (&mutex); -} - -bool WaitableEvent::wait (int timeOutMillisecs) const noexcept -{ - pthread_mutex_lock (&mutex); - - if (! triggered) - { - if (timeOutMillisecs < 0) - { - do - { - pthread_cond_wait (&condition, &mutex); - } - while (! triggered); - } - else - { - struct timeval now; - gettimeofday (&now, nullptr); - - struct timespec time; - time.tv_sec = now.tv_sec + (timeOutMillisecs / 1000); - time.tv_nsec = (now.tv_usec + ((timeOutMillisecs % 1000) * 1000)) * 1000; - - if (time.tv_nsec >= 1000000000) - { - time.tv_nsec -= 1000000000; - time.tv_sec++; - } - - do - { - if (pthread_cond_timedwait (&condition, &mutex, &time) == ETIMEDOUT) - { - pthread_mutex_unlock (&mutex); - return false; - } - } - while (! triggered); - } - } - - if (! manualReset) - triggered = false; - - pthread_mutex_unlock (&mutex); - return true; -} - -void WaitableEvent::signal() const noexcept -{ - pthread_mutex_lock (&mutex); - - if (! triggered) - { - triggered = true; - pthread_cond_broadcast (&condition); - } - - pthread_mutex_unlock (&mutex); -} - -void WaitableEvent::reset() const noexcept -{ - pthread_mutex_lock (&mutex); - triggered = false; - pthread_mutex_unlock (&mutex); -} - //============================================================================== void JUCE_CALLTYPE Thread::sleep (int millisecs) { @@ -1242,7 +1153,7 @@ public: if (numBytesRead > 0 || feof (readHandle)) return numBytesRead; - // signal occured during fread() so try again + // signal occurred during fread() so try again if (ferror (readHandle) && errno == EINTR) continue; diff --git a/modules/juce_core/native/juce_win32_SystemStats.cpp b/modules/juce_core/native/juce_win32_SystemStats.cpp index fa0befe2..5c74c207 100644 --- a/modules/juce_core/native/juce_win32_SystemStats.cpp +++ b/modules/juce_core/native/juce_win32_SystemStats.cpp @@ -144,11 +144,15 @@ void CPUInformation::initialise() noexcept hasSSE2 = (info[3] & (1 << 26)) != 0; hasSSE3 = (info[2] & (1 << 0)) != 0; hasAVX = (info[2] & (1 << 28)) != 0; + hasFMA3 = (info[2] & (1 << 12)) != 0; hasSSSE3 = (info[2] & (1 << 9)) != 0; hasSSE41 = (info[2] & (1 << 19)) != 0; hasSSE42 = (info[2] & (1 << 20)) != 0; has3DNow = (info[1] & (1 << 31)) != 0; + callCPUID (info, 0x80000001); + hasFMA4 = (info[2] & (1 << 16)) != 0; + callCPUID (info, 7); hasAVX2 = (info[1] & (1 << 5)) != 0; @@ -185,32 +189,63 @@ static DebugFlagsInitialiser debugFlagsInitialiser; #endif //============================================================================== -RTL_OSVERSIONINFOW getWindowsVersionInfo() -{ - RTL_OSVERSIONINFOW versionInfo = { 0 }; - - if (auto* moduleHandle = ::GetModuleHandleW (L"ntdll.dll")) - { - using RtlGetVersion = LONG (WINAPI*) (PRTL_OSVERSIONINFOW); - - if (auto* rtlGetVersion = (RtlGetVersion) ::GetProcAddress (moduleHandle, "RtlGetVersion")) - { - versionInfo.dwOSVersionInfoSize = sizeof (versionInfo); - LONG STATUS_SUCCESS = 0; - - if (rtlGetVersion (&versionInfo) != STATUS_SUCCESS) - versionInfo = { 0 }; - } - } - - return versionInfo; -} +#if JUCE_MINGW + static uint32 getWindowsVersion() + { + auto filename = _T("kernel32.dll"); + DWORD handle = 0; + + if (auto size = GetFileVersionInfoSize (filename, &handle)) + { + HeapBlock data (size); + + if (GetFileVersionInfo (filename, handle, size, data)) + { + VS_FIXEDFILEINFO* info = nullptr; + UINT verSize = 0; + + if (VerQueryValue (data, (LPCTSTR) _T("\\"), (void**) &info, &verSize)) + if (size > 0 && info != nullptr && info->dwSignature == 0xfeef04bd) + return (uint32) info->dwFileVersionMS; + } + } + + return 0; + } +#else + RTL_OSVERSIONINFOW getWindowsVersionInfo() + { + RTL_OSVERSIONINFOW versionInfo = { 0 }; + + if (auto* moduleHandle = ::GetModuleHandleW (L"ntdll.dll")) + { + using RtlGetVersion = LONG (WINAPI*) (PRTL_OSVERSIONINFOW); + + if (auto* rtlGetVersion = (RtlGetVersion) ::GetProcAddress (moduleHandle, "RtlGetVersion")) + { + versionInfo.dwOSVersionInfoSize = sizeof (versionInfo); + LONG STATUS_SUCCESS = 0; + + if (rtlGetVersion (&versionInfo) != STATUS_SUCCESS) + versionInfo = { 0 }; + } + } + + return versionInfo; + } +#endif SystemStats::OperatingSystemType SystemStats::getOperatingSystemType() { + #if JUCE_MINGW + auto v = getWindowsVersion(); + auto major = (v >> 16) & 0xff; + auto minor = (v >> 0) & 0xff; + #else auto versionInfo = getWindowsVersionInfo(); auto major = versionInfo.dwMajorVersion; auto minor = versionInfo.dwMinorVersion; + #endif jassert (major <= 10); // need to add support for new version! diff --git a/modules/juce_core/native/juce_win32_Threads.cpp b/modules/juce_core/native/juce_win32_Threads.cpp index aa826d01..749bf747 100644 --- a/modules/juce_core/native/juce_win32_Threads.cpp +++ b/modules/juce_core/native/juce_win32_Threads.cpp @@ -48,20 +48,6 @@ bool CriticalSection::tryEnter() const noexcept { return TryEnterCriticalSec void CriticalSection::exit() const noexcept { LeaveCriticalSection ((CRITICAL_SECTION*) lock); } -//============================================================================== -WaitableEvent::WaitableEvent (const bool manualReset) noexcept - : handle (CreateEvent (0, manualReset ? TRUE : FALSE, FALSE, 0)) {} - -WaitableEvent::~WaitableEvent() noexcept { CloseHandle (handle); } - -void WaitableEvent::signal() const noexcept { SetEvent (handle); } -void WaitableEvent::reset() const noexcept { ResetEvent (handle); } - -bool WaitableEvent::wait (const int timeOutMs) const noexcept -{ - return WaitForSingleObject (handle, (DWORD) timeOutMs) == WAIT_OBJECT_0; -} - //============================================================================== void JUCE_API juce_threadEntryPoint (void*); @@ -258,15 +244,8 @@ void JUCE_CALLTYPE Process::setCurrentModuleInstanceHandle (void* const newHandl currentModuleHandle = newHandle; } -void JUCE_CALLTYPE Process::raisePrivilege() -{ - jassertfalse; // xxx not implemented -} - -void JUCE_CALLTYPE Process::lowerPrivilege() -{ - jassertfalse; // xxx not implemented -} +void JUCE_CALLTYPE Process::raisePrivilege() {} +void JUCE_CALLTYPE Process::lowerPrivilege() {} void JUCE_CALLTYPE Process::terminate() { diff --git a/modules/juce_core/network/juce_Socket.cpp b/modules/juce_core/network/juce_Socket.cpp index 1c15fc56..1e28be5a 100644 --- a/modules/juce_core/network/juce_Socket.cpp +++ b/modules/juce_core/network/juce_Socket.cpp @@ -36,9 +36,6 @@ namespace juce using juce_socklen_t = int; using juce_recvsend_size_t = int; using SocketHandle = SOCKET; - #if ! JUCE_MINGW - using pollfd = WSAPOLLFD; - #endif static const SocketHandle invalidSocket = INVALID_SOCKET; #elif JUCE_ANDROID using juce_socklen_t = socklen_t; @@ -286,9 +283,25 @@ namespace SocketHelpers if (! lock.isLocked()) return -1; + auto hasErrorOccurred = [&handle] () -> bool + { + auto h = handle.load(); + + if (h == invalidSocket) + return true; + + int opt; + juce_socklen_t len = sizeof (opt); + + if (getsockopt (h, SOL_SOCKET, SO_ERROR, (char*) &opt, &len) < 0 || opt != 0) + return true; + + return false; + }; + auto h = handle.load(); - #if JUCE_MINGW + #if JUCE_WINDOWS || JUCE_MINGW struct timeval timeout; struct timeval* timeoutp; @@ -309,12 +322,15 @@ namespace SocketHelpers FD_ZERO (&wset); FD_SET (h, &wset); - fd_set* const prset = forReading ? &rset : nullptr; - fd_set* const pwset = forReading ? nullptr : &wset; + fd_set* prset = forReading ? &rset : nullptr; + fd_set* pwset = forReading ? nullptr : &wset; - if (select ((int) h + 1, prset, pwset, 0, timeoutp) < 0) + // NB - need to use select() here as WSAPoll is broken on Windows + if (select ((int) h + 1, prset, pwset, nullptr, timeoutp) < 0 || hasErrorOccurred()) return -1; - #else + + return FD_ISSET (h, forReading ? &rset : &wset) ? 1 : 0; + #else short eventsFlag = (forReading ? POLLIN : POLLOUT); pollfd pfd { (SocketHandle) h, eventsFlag, 0 }; @@ -322,46 +338,17 @@ namespace SocketHelpers for (;;) { - #if JUCE_WINDOWS - result = WSAPoll (&pfd, 1, timeoutMsecs); - #else result = poll (&pfd, 1, timeoutMsecs); - #endif - if (result >= 0 - #if JUCE_WINDOWS - || result == SOCKET_ERROR - #else - || errno != EINTR - #endif - ) - { + if (result >= 0 || errno != EINTR) break; - } } - if (result < 0) - return -1; - #endif - - // we are closing - if (handle.load() < 0) + if (result < 0 || hasErrorOccurred()) return -1; - { - int opt; - juce_socklen_t len = sizeof (opt); - - if (getsockopt (h, SOL_SOCKET, SO_ERROR, (char*) &opt, &len) < 0 - || opt != 0) - return -1; - } - - #if JUCE_MINGW - return FD_ISSET (h, forReading ? &rset : &wset) ? 1 : 0; - #else return (pfd.revents & eventsFlag) != 0; - #endif + #endif } static addrinfo* getAddressInfo (bool isDatagram, const String& hostName, int portNumber) diff --git a/modules/juce_core/network/juce_URL.cpp b/modules/juce_core/network/juce_URL.cpp index 26169129..56f2a3ce 100644 --- a/modules/juce_core/network/juce_URL.cpp +++ b/modules/juce_core/network/juce_URL.cpp @@ -82,7 +82,7 @@ struct FallbackDownloadTask : public URL::DownloadTask, break; } - fileStream->flush(); + fileStream.reset(); if (threadShouldExit() || stream->isError()) error = true; @@ -97,7 +97,7 @@ struct FallbackDownloadTask : public URL::DownloadTask, } //============================================================================== - const std::unique_ptr fileStream; + std::unique_ptr fileStream; const std::unique_ptr stream; const size_t bufferSize; HeapBlock buffer; diff --git a/modules/juce_core/network/juce_WebInputStream.h b/modules/juce_core/network/juce_WebInputStream.h index 18602e7b..b4a81944 100644 --- a/modules/juce_core/network/juce_WebInputStream.h +++ b/modules/juce_core/network/juce_WebInputStream.h @@ -190,10 +190,10 @@ class JUCE_API WebInputStream : public InputStream The position is an absolute number of bytes from the stream's start. For a WebInputStream, this method will fail if wantedPos is smaller - than the curent position. If wantedPos is greater than the current + than the current position. If wantedPos is greater than the current position, then calling setPosition is the same as calling read, i.e. the skipped data will still be downloaded, although skipped bytes will - be discarded immedietely. + be discarded immediately. @returns true if the stream manages to reposition itself correctly @see getPosition diff --git a/modules/juce_core/streams/juce_MemoryOutputStream.h b/modules/juce_core/streams/juce_MemoryOutputStream.h index 0a248030..231a7f5f 100644 --- a/modules/juce_core/streams/juce_MemoryOutputStream.h +++ b/modules/juce_core/streams/juce_MemoryOutputStream.h @@ -45,7 +45,7 @@ public: Note that the destination block will always be larger than the amount of data that has been written to the stream, because the MemoryOutputStream keeps some - spare capactity at its end. To trim the block's size down to fit the actual + spare capacity at its end. To trim the block's size down to fit the actual data, call flush(), or delete the MemoryOutputStream. @param memoryBlockToWriteTo the block into which new data will be written. diff --git a/modules/juce_core/system/juce_StandardHeader.h b/modules/juce_core/system/juce_StandardHeader.h index 34aed373..68c81a03 100644 --- a/modules/juce_core/system/juce_StandardHeader.h +++ b/modules/juce_core/system/juce_StandardHeader.h @@ -29,7 +29,7 @@ */ #define JUCE_MAJOR_VERSION 5 #define JUCE_MINOR_VERSION 4 -#define JUCE_BUILDNUMBER 5 +#define JUCE_BUILDNUMBER 6 /** Current JUCE version number. @@ -54,6 +54,11 @@ #include #include #include +#include +#include +#include +#include +#include //============================================================================== #include "juce_CompilerSupport.h" @@ -115,11 +120,6 @@ #undef minor #undef KeyPress -// Include a replacement for std::function -#if JUCE_PROJUCER_LIVE_BUILD - #include "../misc/juce_StdFunctionCompat.h" -#endif - //============================================================================== // DLL building settings on Windows #if JUCE_MSVC diff --git a/modules/juce_core/system/juce_SystemStats.cpp b/modules/juce_core/system/juce_SystemStats.cpp index 0520840c..2ea90f80 100644 --- a/modules/juce_core/system/juce_SystemStats.cpp +++ b/modules/juce_core/system/juce_SystemStats.cpp @@ -90,9 +90,9 @@ struct CPUInformation int numLogicalCPUs = 0, numPhysicalCPUs = 0; - bool hasMMX = false, hasSSE = false, hasSSE2 = false, hasSSE3 = false, - has3DNow = false, hasSSSE3 = false, hasSSE41 = false, - hasSSE42 = false, hasAVX = false, hasAVX2 = false, + bool hasMMX = false, hasSSE = false, hasSSE2 = false, hasSSE3 = false, + has3DNow = false, hasFMA3 = false, hasFMA4 = false, hasSSSE3 = false, + hasSSE41 = false, hasSSE42 = false, hasAVX = false, hasAVX2 = false, hasAVX512F = false, hasAVX512BW = false, hasAVX512CD = false, hasAVX512DQ = false, hasAVX512ER = false, hasAVX512IFMA = false, hasAVX512PF = false, hasAVX512VBMI = false, hasAVX512VL = false, @@ -110,6 +110,8 @@ int SystemStats::getNumCpus() noexcept { return getCPUInformation().num int SystemStats::getNumPhysicalCpus() noexcept { return getCPUInformation().numPhysicalCPUs; } bool SystemStats::hasMMX() noexcept { return getCPUInformation().hasMMX; } bool SystemStats::has3DNow() noexcept { return getCPUInformation().has3DNow; } +bool SystemStats::hasFMA3() noexcept { return getCPUInformation().hasFMA3; } +bool SystemStats::hasFMA4() noexcept { return getCPUInformation().hasFMA4; } bool SystemStats::hasSSE() noexcept { return getCPUInformation().hasSSE; } bool SystemStats::hasSSE2() noexcept { return getCPUInformation().hasSSE2; } bool SystemStats::hasSSE3() noexcept { return getCPUInformation().hasSSE3; } diff --git a/modules/juce_core/system/juce_SystemStats.h b/modules/juce_core/system/juce_SystemStats.h index 9234a23a..7926c32b 100644 --- a/modules/juce_core/system/juce_SystemStats.h +++ b/modules/juce_core/system/juce_SystemStats.h @@ -172,6 +172,8 @@ public: 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 hasFMA3() noexcept; /**< Returns true if AMD FMA3 instructions are available. */ + static bool hasFMA4() noexcept; /**< Returns true if AMD FMA4 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 SSE3 instructions are available. */ diff --git a/modules/juce_core/text/juce_LocalisedStrings.h b/modules/juce_core/text/juce_LocalisedStrings.h index 1ff0e474..195341e0 100644 --- a/modules/juce_core/text/juce_LocalisedStrings.h +++ b/modules/juce_core/text/juce_LocalisedStrings.h @@ -161,7 +161,7 @@ public: countries: fr be mc ch lu @endcode - The country codes are supposed to be 2-character ISO complient codes. + The country codes are supposed to be 2-character ISO compliant codes. */ const StringArray& getCountryCodes() const { return countryCodes; } diff --git a/modules/juce_core/threads/juce_Process.h b/modules/juce_core/threads/juce_Process.h index 726fa193..bc868ef7 100644 --- a/modules/juce_core/threads/juce_Process.h +++ b/modules/juce_core/threads/juce_Process.h @@ -133,7 +133,7 @@ public: static void JUCE_CALLTYPE setCurrentModuleInstanceHandle (void* newHandle) noexcept; #endif - #if JUCE_MAC || DOXYGEN + #if (JUCE_MAC && JUCE_MODULE_AVAILABLE_juce_gui_basics) || DOXYGEN //============================================================================== /** OSX ONLY - Shows or hides the OSX dock icon for this app. */ static void setDockIconVisible (bool isVisible); diff --git a/modules/juce_core/threads/juce_ReadWriteLock.cpp b/modules/juce_core/threads/juce_ReadWriteLock.cpp index af607b7f..86f6afe2 100644 --- a/modules/juce_core/threads/juce_ReadWriteLock.cpp +++ b/modules/juce_core/threads/juce_ReadWriteLock.cpp @@ -38,22 +38,20 @@ ReadWriteLock::~ReadWriteLock() noexcept void ReadWriteLock::enterRead() const noexcept { while (! tryEnterRead()) - waitEvent.wait (100); + readWaitEvent.wait (100); } bool ReadWriteLock::tryEnterRead() const noexcept { - const Thread::ThreadID threadId = Thread::getCurrentThreadId(); + auto threadId = Thread::getCurrentThreadId(); const SpinLock::ScopedLockType sl (accessLock); - for (int i = 0; i < readerThreads.size(); ++i) + for (auto& readerThread : readerThreads) { - ThreadRecursionCount& trc = readerThreads.getReference(i); - - if (trc.threadID == threadId) + if (readerThread.threadID == threadId) { - trc.count++; + readerThread.count++; return true; } } @@ -61,8 +59,7 @@ bool ReadWriteLock::tryEnterRead() const noexcept if (numWriters + numWaitingWriters == 0 || (threadId == writerThreadId && numWriters > 0)) { - ThreadRecursionCount trc = { threadId, 1 }; - readerThreads.add (trc); + readerThreads.add ({ threadId, 1 }); return true; } @@ -71,19 +68,21 @@ bool ReadWriteLock::tryEnterRead() const noexcept void ReadWriteLock::exitRead() const noexcept { - const Thread::ThreadID threadId = Thread::getCurrentThreadId(); + auto threadId = Thread::getCurrentThreadId(); const SpinLock::ScopedLockType sl (accessLock); for (int i = 0; i < readerThreads.size(); ++i) { - ThreadRecursionCount& trc = readerThreads.getReference(i); + auto& readerThread = readerThreads.getReference (i); - if (trc.threadID == threadId) + if (readerThread.threadID == threadId) { - if (--(trc.count) == 0) + if (--(readerThread.count) == 0) { readerThreads.remove (i); - waitEvent.signal(); + + readWaitEvent.signal(); + writeWaitEvent.signal(); } return; @@ -96,14 +95,14 @@ void ReadWriteLock::exitRead() const noexcept //============================================================================== void ReadWriteLock::enterWrite() const noexcept { - const Thread::ThreadID threadId = Thread::getCurrentThreadId(); + auto threadId = Thread::getCurrentThreadId(); const SpinLock::ScopedLockType sl (accessLock); while (! tryEnterWriteInternal (threadId)) { ++numWaitingWriters; accessLock.exit(); - waitEvent.wait (100); + writeWaitEvent.wait (100); accessLock.enter(); --numWaitingWriters; } @@ -119,7 +118,7 @@ bool ReadWriteLock::tryEnterWriteInternal (Thread::ThreadID threadId) const noex { if (readerThreads.size() + numWriters == 0 || threadId == writerThreadId - || (readerThreads.size() == 1 && readerThreads.getReference(0).threadID == threadId)) + || (readerThreads.size() == 1 && readerThreads.getReference (0).threadID == threadId)) { writerThreadId = threadId; ++numWriters; @@ -139,7 +138,9 @@ void ReadWriteLock::exitWrite() const noexcept if (--numWriters == 0) { writerThreadId = {}; - waitEvent.signal(); + + readWaitEvent.signal(); + writeWaitEvent.signal(); } } diff --git a/modules/juce_core/threads/juce_ReadWriteLock.h b/modules/juce_core/threads/juce_ReadWriteLock.h index c954a874..28c5b725 100644 --- a/modules/juce_core/threads/juce_ReadWriteLock.h +++ b/modules/juce_core/threads/juce_ReadWriteLock.h @@ -126,7 +126,7 @@ public: private: //============================================================================== SpinLock accessLock; - WaitableEvent waitEvent; + WaitableEvent readWaitEvent, writeWaitEvent; mutable int numWaitingWriters = 0, numWriters = 0; mutable Thread::ThreadID writerThreadId = {}; diff --git a/modules/juce_core/threads/juce_ThreadPool.h b/modules/juce_core/threads/juce_ThreadPool.h index d39ca67a..21973e13 100644 --- a/modules/juce_core/threads/juce_ThreadPool.h +++ b/modules/juce_core/threads/juce_ThreadPool.h @@ -76,7 +76,7 @@ public: again when a thread is free. */ }; - /** Peforms the actual work that this job needs to do. + /** Performs the actual work that this job needs to do. Your subclass must implement this method, in which is does its work. diff --git a/modules/juce_core/threads/juce_TimeSliceThread.h b/modules/juce_core/threads/juce_TimeSliceThread.h index 61b0ea2f..f661cff3 100644 --- a/modules/juce_core/threads/juce_TimeSliceThread.h +++ b/modules/juce_core/threads/juce_TimeSliceThread.h @@ -57,7 +57,7 @@ public: @returns Your method should return the number of milliseconds which it would like to wait before being called again. Returning 0 will make the thread call again as soon as possible (after possibly servicing other busy clients). If you return a value below zero, your client will be removed from the list of clients, - and won't be called again. The value you specify isn't a guaranteee, and is only used as a hint by the + and won't be called again. The value you specify isn't a guarantee, and is only used as a hint by the thread - the actual time before the next callback may be more or less than specified. You can force the TimeSliceThread to wake up and poll again immediately by calling its notify() method. */ diff --git a/modules/juce_core/threads/juce_WaitableEvent.cpp b/modules/juce_core/threads/juce_WaitableEvent.cpp new file mode 100644 index 00000000..8b01c4db --- /dev/null +++ b/modules/juce_core/threads/juce_WaitableEvent.cpp @@ -0,0 +1,70 @@ +/* + ============================================================================== + + This file is part of the JUCE library. + Copyright (c) 2017 - ROLI Ltd. + + JUCE is an open source library subject to commercial or open-source + licensing. + + The code included in this file is provided under the terms of the ISC license + http://www.isc.org/downloads/software-support-policy/isc-license. Permission + To use, copy, modify, and/or distribute this software for any purpose with or + without fee is hereby granted provided that the above copyright notice and + this permission notice appear in all copies. + + JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER + EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE + DISCLAIMED. + + ============================================================================== +*/ + +namespace juce +{ + +WaitableEvent::WaitableEvent (bool manualReset) noexcept + : useManualReset (manualReset) +{ +} + +bool WaitableEvent::wait (int timeOutMilliseconds) const +{ + std::unique_lock lock (mutex); + + if (! triggered) + { + if (timeOutMilliseconds < 0) + { + condition.wait (lock, [this] { return triggered == true; }); + } + else + { + if (! condition.wait_for (lock, std::chrono::milliseconds (timeOutMilliseconds), + [this] { return triggered == true; })) + { + return false; + } + } + } + + if (! useManualReset) + reset(); + + return true; +} + +void WaitableEvent::signal() const +{ + std::unique_lock lock (mutex); + + triggered = true; + condition.notify_all(); +} + +void WaitableEvent::reset() const +{ + triggered = false; +} + +} // namespace juce diff --git a/modules/juce_core/threads/juce_WaitableEvent.h b/modules/juce_core/threads/juce_WaitableEvent.h index 012b83ac..3e31a977 100644 --- a/modules/juce_core/threads/juce_WaitableEvent.h +++ b/modules/juce_core/threads/juce_WaitableEvent.h @@ -46,13 +46,6 @@ public: */ explicit WaitableEvent (bool manualReset = false) noexcept; - /** Destructor. - - If other threads are waiting on this object when it gets deleted, this - can cause nasty errors, so be careful! - */ - ~WaitableEvent() noexcept; - //============================================================================== /** Suspends the calling thread until the event has been signalled. @@ -68,9 +61,8 @@ public: @returns true if the object has been signalled, false if the timeout expires first. @see signal, reset */ - bool wait (int timeOutMilliseconds = -1) const noexcept; + bool wait (int timeOutMilliseconds = -1) const; - //============================================================================== /** Wakes up any threads that are currently waiting on this object. If signal() is called when nothing is waiting, the next thread to call wait() @@ -86,24 +78,20 @@ public: @see wait, reset */ - void signal() const noexcept; + void signal() const; - //============================================================================== /** Resets the event to an unsignalled state. If it's not already signalled, this does nothing. */ - void reset() const noexcept; - + void reset() const; private: //============================================================================== - #if JUCE_WINDOWS - void* handle; - #else - mutable pthread_cond_t condition; - mutable pthread_mutex_t mutex; - mutable bool triggered, manualReset; - #endif + bool useManualReset; + + mutable std::mutex mutex; + mutable std::condition_variable condition; + mutable std::atomic triggered { false }; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (WaitableEvent) }; diff --git a/modules/juce_core/zip/juce_ZipFile.cpp b/modules/juce_core/zip/juce_ZipFile.cpp index 16b9cbe2..4c492255 100644 --- a/modules/juce_core/zip/juce_ZipFile.cpp +++ b/modules/juce_core/zip/juce_ZipFile.cpp @@ -46,10 +46,10 @@ struct ZipFile::ZipEntryHolder entry.uncompressedSize = (int64) readUnalignedLittleEndianInt (buffer + 24); streamOffset = (int64) readUnalignedLittleEndianInt (buffer + 42); - auto externalFileAttributes = (int32) readUnalignedLittleEndianInt (buffer + 38); - auto fileType = (externalFileAttributes >> 28) & 0xf; - + entry.externalFileAttributes = readUnalignedLittleEndianInt (buffer + 38); + auto fileType = (entry.externalFileAttributes >> 28) & 0xf; entry.isSymbolicLink = (fileType == 0xA); + entry.filename = String::fromUTF8 (buffer + 46, fileNameLen); } diff --git a/modules/juce_core/zip/juce_ZipFile.h b/modules/juce_core/zip/juce_ZipFile.h index 45173daa..e3f8b764 100644 --- a/modules/juce_core/zip/juce_ZipFile.h +++ b/modules/juce_core/zip/juce_ZipFile.h @@ -82,6 +82,12 @@ public: /** True if the zip entry is a symbolic link. */ bool isSymbolicLink; + + /** Platform specific data. Depending on how the zip file was created this + may contain macOS and Linux file types, permissions and + setuid/setgid/sticky bits. + */ + uint32 externalFileAttributes; }; //============================================================================== diff --git a/modules/juce_cryptography/encryption/juce_BlowFish.h b/modules/juce_cryptography/encryption/juce_BlowFish.h index f6cd04bc..57ab8c63 100644 --- a/modules/juce_cryptography/encryption/juce_BlowFish.h +++ b/modules/juce_cryptography/encryption/juce_BlowFish.h @@ -73,11 +73,11 @@ public: @param buffer The message that should be encrypted. See bufferSize on size requirements! @param sizeOfMsg The size of the message that should be encrypted in bytes - @param bufferSize The size of the buffer in bytes. To accommodate the encypted + @param bufferSize The size of the buffer in bytes. To accommodate the encrypted data, the buffer must be larger than the message: the size of the buffer needs to be equal or greater than the size of the - message in bytes rounded to the next integer which is divisable - by eight. If the message size in bytes is already divisable by eight + message in bytes rounded to the next integer which is divisible + by eight. If the message size in bytes is already divisible by eight then you need to add eight bytes to the buffer size. If in doubt simply use bufferSize = sizeOfMsg + 8. diff --git a/modules/juce_cryptography/juce_cryptography.h b/modules/juce_cryptography/juce_cryptography.h index 86d5ca36..3ecee082 100644 --- a/modules/juce_cryptography/juce_cryptography.h +++ b/modules/juce_cryptography/juce_cryptography.h @@ -24,6 +24,7 @@ ============================================================================== */ + /******************************************************************************* The block below describes the properties of this module, and is read by the Projucer to automatically generate project code that uses it. @@ -33,15 +34,15 @@ BEGIN_JUCE_MODULE_DECLARATION - ID: juce_cryptography - vendor: juce - version: 5.4.5 - name: JUCE cryptography classes - description: Classes for various basic cryptography functions, including RSA, Blowfish, MD5, SHA, etc. - website: http://www.juce.com/juce - license: GPL/Commercial + ID: juce_cryptography + vendor: juce + version: 5.4.6 + name: JUCE cryptography classes + description: Classes for various basic cryptography functions, including RSA, Blowfish, MD5, SHA, etc. + website: http://www.juce.com/juce + license: GPL/Commercial - dependencies: juce_core + dependencies: juce_core END_JUCE_MODULE_DECLARATION diff --git a/modules/juce_data_structures/juce_data_structures.h b/modules/juce_data_structures/juce_data_structures.h index 85ec23f5..e838b11e 100644 --- a/modules/juce_data_structures/juce_data_structures.h +++ b/modules/juce_data_structures/juce_data_structures.h @@ -24,6 +24,7 @@ ============================================================================== */ + /******************************************************************************* The block below describes the properties of this module, and is read by the Projucer to automatically generate project code that uses it. @@ -33,15 +34,15 @@ BEGIN_JUCE_MODULE_DECLARATION - ID: juce_data_structures - vendor: juce - version: 5.4.5 - name: JUCE data model helper classes - description: Classes for undo/redo management, and smart data structures. - website: http://www.juce.com/juce - license: GPL/Commercial + ID: juce_data_structures + vendor: juce + version: 5.4.6 + name: JUCE data model helper classes + description: Classes for undo/redo management, and smart data structures. + website: http://www.juce.com/juce + license: GPL/Commercial - dependencies: juce_events + dependencies: juce_events END_JUCE_MODULE_DECLARATION diff --git a/modules/juce_data_structures/values/juce_ValueTree.h b/modules/juce_data_structures/values/juce_ValueTree.h index 1145a68a..0f4f725a 100644 --- a/modules/juce_data_structures/values/juce_ValueTree.h +++ b/modules/juce_data_structures/values/juce_ValueTree.h @@ -62,7 +62,7 @@ namespace juce will correspond to the order in which the property was added, or that it will remain constant when other properties are added or removed. - Listeners can be added to a ValueTree to be told when properies change and when + Listeners can be added to a ValueTree to be told when properties change and when sub-trees are added or removed. @see var, XmlElement diff --git a/modules/juce_dsp/containers/juce_AudioBlock.h b/modules/juce_dsp/containers/juce_AudioBlock.h index 7f289cdf..b8c0074b 100644 --- a/modules/juce_dsp/containers/juce_AudioBlock.h +++ b/modules/juce_dsp/containers/juce_AudioBlock.h @@ -234,7 +234,7 @@ public: return AudioBlock (channels + channel, 1, startSample, numSamples); } - /** Returns a subset of continguous channels + /** Returns a subset of contiguous channels @param channelStart First channel of the subset @param numChannelsToUse Count of channels in the subset */ @@ -288,8 +288,8 @@ public: const AudioBlock& clear() const noexcept { clearInternal(); return *this; } /** Fills the memory referenced by this AudioBlock with value. */ - AudioBlock& JUCE_VECTOR_CALLTYPE fill (SampleType value) noexcept { fillInternal (value); return *this; } - const AudioBlock& JUCE_VECTOR_CALLTYPE fill (SampleType value) const noexcept { fillInternal (value); return *this; } + AudioBlock& JUCE_VECTOR_CALLTYPE fill (NumericType value) noexcept { fillInternal (value); return *this; } + const AudioBlock& JUCE_VECTOR_CALLTYPE fill (NumericType value) const noexcept { fillInternal (value); return *this; } /** Copies the values in src to this block. */ template @@ -297,25 +297,25 @@ public: template const AudioBlock& copyFrom (const AudioBlock& src) const noexcept { copyFromInternal (src); return *this; } - /** Copy the values from a JUCE's AudioBuffer to this block. + /** Copy the values from an AudioBuffer to this block. - All indices and sizes are in the receiver's units, i.e. if SampleType is a + All indices and sizes are in this AudioBlock's units, i.e. if SampleType is a SIMDRegister then incrementing srcPos by one will increase the sample position in the AudioBuffer's units by a factor of SIMDRegister::SIMDNumElements. */ - template - AudioBlock& copyFrom (const AudioBuffer& src, + template + AudioBlock& copyFrom (const AudioBuffer& src, size_t srcPos = 0, size_t dstPos = 0, size_t numElements = std::numeric_limits::max()) { copyFromInternal (src, srcPos, dstPos, numElements); return *this; } - template - const AudioBlock& copyFrom (const AudioBuffer& src, + template + const AudioBlock& copyFrom (const AudioBuffer& src, size_t srcPos = 0, size_t dstPos = 0, size_t numElements = std::numeric_limits::max()) const { copyFromInternal (src, srcPos, dstPos, numElements); return *this; } /** Copies the values from this block to an AudioBuffer. - All indices and sizes are in the receiver's units, i.e. if SampleType is a + All indices and sizes are in this AudioBlock's units, i.e. if SampleType is a SIMDRegister then incrementing dstPos by one will increase the sample position in the AudioBuffer's units by a factor of SIMDRegister::SIMDNumElements. */ @@ -329,7 +329,8 @@ public: for (size_t ch = 0; ch < maxChannels; ++ch) FloatVectorOperations::copy (dst.getWritePointer (static_cast (ch), static_cast (dstPos * sizeFactor)), - getChannelPointer (ch) + srcPos, n); + getDataPointer (ch) + (srcPos * sizeFactor), + n); } /** Move memory within this block from the position srcPos to the position dstPos. @@ -375,8 +376,8 @@ public: //============================================================================== /** Adds a fixed value to the elements in this block. */ - AudioBlock& JUCE_VECTOR_CALLTYPE add (SampleType value) noexcept { addInternal (value); return *this; } - const AudioBlock& JUCE_VECTOR_CALLTYPE add (SampleType value) const noexcept { addInternal (value); return *this; } + AudioBlock& JUCE_VECTOR_CALLTYPE add (NumericType value) noexcept { addInternal (value); return *this; } + const AudioBlock& JUCE_VECTOR_CALLTYPE add (NumericType value) const noexcept { addInternal (value); return *this; } /** Adds the elements in the src block to the elements in this block. */ template @@ -386,9 +387,9 @@ public: /** Adds a fixed value to each source value and replaces the contents of this block. */ template - AudioBlock& JUCE_VECTOR_CALLTYPE replaceWithSumOf (AudioBlock src, SampleType value) noexcept { replaceWithSumOfInternal (src, value); return *this; } + AudioBlock& JUCE_VECTOR_CALLTYPE replaceWithSumOf (AudioBlock src, NumericType value) noexcept { replaceWithSumOfInternal (src, value); return *this; } template - const AudioBlock& JUCE_VECTOR_CALLTYPE replaceWithSumOf (AudioBlock src, SampleType value) const noexcept { replaceWithSumOfInternal (src, value); return *this; } + const AudioBlock& JUCE_VECTOR_CALLTYPE replaceWithSumOf (AudioBlock src, NumericType value) const noexcept { replaceWithSumOfInternal (src, value); return *this; } /** Adds each source1 value to the corresponding source2 value and replaces the contents of this block. */ template @@ -398,8 +399,8 @@ public: //============================================================================== /** Subtracts a fixed value from the elements in this block. */ - AudioBlock& JUCE_VECTOR_CALLTYPE subtract (SampleType value) noexcept { subtractInternal (value); return *this; } - const AudioBlock& JUCE_VECTOR_CALLTYPE subtract (SampleType value) const noexcept { subtractInternal (value); return *this; } + AudioBlock& JUCE_VECTOR_CALLTYPE subtract (NumericType value) noexcept { subtractInternal (value); return *this; } + const AudioBlock& JUCE_VECTOR_CALLTYPE subtract (NumericType value) const noexcept { subtractInternal (value); return *this; } /** Subtracts the source values from the elements in this block. */ template @@ -409,9 +410,9 @@ public: /** Subtracts a fixed value from each source value and replaces the contents of this block. */ template - AudioBlock& JUCE_VECTOR_CALLTYPE replaceWithDifferenceOf (AudioBlock src, SampleType value) noexcept { replaceWithDifferenceOfInternal (src, value); return *this; } + AudioBlock& JUCE_VECTOR_CALLTYPE replaceWithDifferenceOf (AudioBlock src, NumericType value) noexcept { replaceWithDifferenceOfInternal (src, value); return *this; } template - const AudioBlock& JUCE_VECTOR_CALLTYPE replaceWithDifferenceOf (AudioBlock src, SampleType value) const noexcept { replaceWithDifferenceOfInternal (src, value); return *this; } + const AudioBlock& JUCE_VECTOR_CALLTYPE replaceWithDifferenceOf (AudioBlock src, NumericType value) const noexcept { replaceWithDifferenceOfInternal (src, value); return *this; } /** Subtracts each source2 value from the corresponding source1 value and replaces the contents of this block. */ template @@ -421,8 +422,8 @@ public: //============================================================================== /** Multiplies the elements in this block by a fixed value. */ - AudioBlock& JUCE_VECTOR_CALLTYPE multiplyBy (SampleType value) noexcept { multiplyByInternal (value); return *this; } - const AudioBlock& JUCE_VECTOR_CALLTYPE multiplyBy (SampleType value) const noexcept { multiplyByInternal (value); return *this; } + AudioBlock& JUCE_VECTOR_CALLTYPE multiplyBy (NumericType value) noexcept { multiplyByInternal (value); return *this; } + const AudioBlock& JUCE_VECTOR_CALLTYPE multiplyBy (NumericType value) const noexcept { multiplyByInternal (value); return *this; } /** Multiplies the elements in this block by the elements in the src block */ template @@ -432,9 +433,9 @@ public: /** Replaces the elements in this block with the product of the elements in the source src block and a fixed value. */ template - AudioBlock& JUCE_VECTOR_CALLTYPE replaceWithProductOf (AudioBlock src, SampleType value) noexcept { replaceWithProductOfInternal (src, value); return *this; } + AudioBlock& JUCE_VECTOR_CALLTYPE replaceWithProductOf (AudioBlock src, NumericType value) noexcept { replaceWithProductOfInternal (src, value); return *this; } template - const AudioBlock& JUCE_VECTOR_CALLTYPE replaceWithProductOf (AudioBlock src, SampleType value) const noexcept { replaceWithProductOfInternal (src, value); return *this; } + const AudioBlock& JUCE_VECTOR_CALLTYPE replaceWithProductOf (AudioBlock src, NumericType value) const noexcept { replaceWithProductOfInternal (src, value); return *this; } /** Replaces the elements in this block with the product of the elements in the src1 and scr2 blocks. */ template @@ -458,9 +459,9 @@ public: //============================================================================== /** Multiplies each value in src by a fixed value and adds the result to this block. */ template - AudioBlock& JUCE_VECTOR_CALLTYPE addProductOf (AudioBlock src, SampleType factor) noexcept { addProductOfInternal (src, factor); return *this; } + AudioBlock& JUCE_VECTOR_CALLTYPE addProductOf (AudioBlock src, NumericType factor) noexcept { addProductOfInternal (src, factor); return *this; } template - const AudioBlock& JUCE_VECTOR_CALLTYPE addProductOf (AudioBlock src, SampleType factor) const noexcept { addProductOfInternal (src, factor); return *this; } + const AudioBlock& JUCE_VECTOR_CALLTYPE addProductOf (AudioBlock src, NumericType factor) const noexcept { addProductOfInternal (src, factor); return *this; } /** Multiplies each value in srcA with the corresponding value in srcB and adds the result to this block. */ template @@ -506,30 +507,30 @@ public: return {}; auto n = static_cast (numSamples * sizeFactor); - auto minmax = FloatVectorOperations::findMinAndMax (getChannelPointer (0), n); + auto minmax = FloatVectorOperations::findMinAndMax (getDataPointer (0), n); for (size_t ch = 1; ch < numChannels; ++ch) - minmax = minmax.getUnionWith (FloatVectorOperations::findMinAndMax (getChannelPointer (ch), n)); + minmax = minmax.getUnionWith (FloatVectorOperations::findMinAndMax (getDataPointer (ch), n)); return minmax; } //============================================================================== // Convenient operator wrappers. - AudioBlock& JUCE_VECTOR_CALLTYPE operator+= (SampleType value) noexcept { return add (value); } - const AudioBlock& JUCE_VECTOR_CALLTYPE operator+= (SampleType value) const noexcept { return add (value); } + AudioBlock& JUCE_VECTOR_CALLTYPE operator+= (NumericType value) noexcept { return add (value); } + const AudioBlock& JUCE_VECTOR_CALLTYPE operator+= (NumericType value) const noexcept { return add (value); } AudioBlock& operator+= (AudioBlock src) noexcept { return add (src); } const AudioBlock& operator+= (AudioBlock src) const noexcept { return add (src); } - AudioBlock& JUCE_VECTOR_CALLTYPE operator-= (SampleType value) noexcept { return subtract (value); } - const AudioBlock& JUCE_VECTOR_CALLTYPE operator-= (SampleType value) const noexcept { return subtract (value); } + AudioBlock& JUCE_VECTOR_CALLTYPE operator-= (NumericType value) noexcept { return subtract (value); } + const AudioBlock& JUCE_VECTOR_CALLTYPE operator-= (NumericType value) const noexcept { return subtract (value); } AudioBlock& operator-= (AudioBlock src) noexcept { return subtract (src); } const AudioBlock& operator-= (AudioBlock src) const noexcept { return subtract (src); } - AudioBlock& JUCE_VECTOR_CALLTYPE operator*= (SampleType value) noexcept { return multiplyBy (value); } - const AudioBlock& JUCE_VECTOR_CALLTYPE operator*= (SampleType value) const noexcept { return multiplyBy (value); } + AudioBlock& JUCE_VECTOR_CALLTYPE operator*= (NumericType value) noexcept { return multiplyBy (value); } + const AudioBlock& JUCE_VECTOR_CALLTYPE operator*= (NumericType value) const noexcept { return multiplyBy (value); } AudioBlock& operator*= (AudioBlock src) noexcept { return multiplyBy (src); } const AudioBlock& operator*= (AudioBlock src) const noexcept { return multiplyBy (src); } @@ -574,42 +575,48 @@ public: } private: + NumericType* getDataPointer (size_t channel) const noexcept + { + return reinterpret_cast (getChannelPointer (channel)); + } + //============================================================================== void JUCE_VECTOR_CALLTYPE clearInternal() const noexcept { auto n = static_cast (numSamples * sizeFactor); for (size_t ch = 0; ch < numChannels; ++ch) - FloatVectorOperations::clear (getChannelPointer (ch), n); + FloatVectorOperations::clear (getDataPointer (ch), n); } - void JUCE_VECTOR_CALLTYPE fillInternal (SampleType value) const noexcept + void JUCE_VECTOR_CALLTYPE fillInternal (NumericType value) const noexcept { auto n = static_cast (numSamples * sizeFactor); for (size_t ch = 0; ch < numChannels; ++ch) - FloatVectorOperations::fill (getChannelPointer (ch), value, n); + FloatVectorOperations::fill (getDataPointer (ch), value, n); } template void copyFromInternal (const AudioBlock& src) const noexcept { auto maxChannels = jmin (src.numChannels, numChannels); - auto n = static_cast (jmin (src.numSamples, numSamples) * sizeFactor); + auto n = static_cast (jmin (src.numSamples * src.sizeFactor, + numSamples * sizeFactor)); for (size_t ch = 0; ch < maxChannels; ++ch) - FloatVectorOperations::copy (getChannelPointer (ch), src.getChannelPointer (ch), n); + FloatVectorOperations::copy (getDataPointer (ch), src.getDataPointer (ch), n); } - template - void copyFromInternal (const AudioBuffer& src, size_t srcPos, size_t dstPos, size_t numElements) const + template + void copyFromInternal (const AudioBuffer& src, size_t srcPos, size_t dstPos, size_t numElements) const { auto srclen = static_cast (src.getNumSamples()) / sizeFactor; auto n = static_cast (jmin (srclen - srcPos, numSamples - dstPos, numElements) * sizeFactor); auto maxChannels = jmin (static_cast (src.getNumChannels()), static_cast (numChannels)); for (size_t ch = 0; ch < maxChannels; ++ch) - FloatVectorOperations::copy (getChannelPointer (ch) + dstPos, + FloatVectorOperations::copy (getDataPointer (ch) + (dstPos * sizeFactor), src.getReadPointer (static_cast (ch), static_cast (srcPos * sizeFactor)), n); @@ -628,12 +635,12 @@ private: } //============================================================================== - void JUCE_VECTOR_CALLTYPE addInternal (SampleType value) const noexcept + void JUCE_VECTOR_CALLTYPE addInternal (NumericType value) const noexcept { auto n = static_cast (numSamples * sizeFactor); for (size_t ch = 0; ch < numChannels; ++ch) - FloatVectorOperations::add (getChannelPointer (ch), value, n); + FloatVectorOperations::add (getDataPointer (ch), value, n); } template @@ -643,17 +650,17 @@ private: auto n = static_cast (jmin (numSamples, src.numSamples) * sizeFactor); for (size_t ch = 0; ch < numChannels; ++ch) - FloatVectorOperations::add (getChannelPointer (ch), src.getChannelPointer (ch), n); + FloatVectorOperations::add (getDataPointer (ch), src.getDataPointer (ch), n); } template - void JUCE_VECTOR_CALLTYPE replaceWithSumOfInternal (AudioBlock src, SampleType value) const noexcept + void JUCE_VECTOR_CALLTYPE replaceWithSumOfInternal (AudioBlock src, NumericType value) const noexcept { jassert (numChannels == src.numChannels); auto n = static_cast (jmin (numSamples, src.numSamples) * sizeFactor); for (size_t ch = 0; ch < numChannels; ++ch) - FloatVectorOperations::add (getChannelPointer (ch), src.getChannelPointer (ch), value, n); + FloatVectorOperations::add (getDataPointer (ch), src.getDataPointer (ch), value, n); } template @@ -663,13 +670,13 @@ private: auto n = static_cast (jmin (numSamples, src1.numSamples, src2.numSamples) * sizeFactor); for (size_t ch = 0; ch < numChannels; ++ch) - FloatVectorOperations::add (getChannelPointer (ch), src1.getChannelPointer (ch), src2.getChannelPointer (ch), n); + FloatVectorOperations::add (getDataPointer (ch), src1.getDataPointer (ch), src2.getDataPointer (ch), n); } //============================================================================== - constexpr void JUCE_VECTOR_CALLTYPE subtractInternal (SampleType value) const noexcept + constexpr void JUCE_VECTOR_CALLTYPE subtractInternal (NumericType value) const noexcept { - addInternal (value * static_cast (-1.0)); + addInternal (value * static_cast (-1.0)); } template @@ -679,13 +686,13 @@ private: auto n = static_cast (jmin (numSamples, src.numSamples) * sizeFactor); for (size_t ch = 0; ch < numChannels; ++ch) - FloatVectorOperations::subtract (getChannelPointer (ch), src.getChannelPointer (ch), n); + FloatVectorOperations::subtract (getDataPointer (ch), src.getDataPointer (ch), n); } template - void JUCE_VECTOR_CALLTYPE replaceWithDifferenceOfInternal (AudioBlock src, SampleType value) const noexcept + void JUCE_VECTOR_CALLTYPE replaceWithDifferenceOfInternal (AudioBlock src, NumericType value) const noexcept { - replaceWithSumOfInternal (src, static_cast (-1.0) * value); + replaceWithSumOfInternal (src, static_cast (-1.0) * value); } template @@ -695,16 +702,16 @@ private: auto n = static_cast (jmin (numSamples, src1.numSamples, src2.numSamples) * sizeFactor); for (size_t ch = 0; ch < numChannels; ++ch) - FloatVectorOperations::subtract (getChannelPointer (ch), src1.getChannelPointer (ch), src2.getChannelPointer (ch), n); + FloatVectorOperations::subtract (getDataPointer (ch), src1.getDataPointer (ch), src2.getDataPointer (ch), n); } //============================================================================== - void JUCE_VECTOR_CALLTYPE multiplyByInternal (SampleType value) const noexcept + void JUCE_VECTOR_CALLTYPE multiplyByInternal (NumericType value) const noexcept { auto n = static_cast (numSamples * sizeFactor); for (size_t ch = 0; ch < numChannels; ++ch) - FloatVectorOperations::multiply (getChannelPointer (ch), value, n); + FloatVectorOperations::multiply (getDataPointer (ch), value, n); } template @@ -714,17 +721,17 @@ private: auto n = static_cast (jmin (numSamples, src.numSamples) * sizeFactor); for (size_t ch = 0; ch < numChannels; ++ch) - FloatVectorOperations::multiply (getChannelPointer (ch), src.getChannelPointer (ch), n); + FloatVectorOperations::multiply (getDataPointer (ch), src.getDataPointer (ch), n); } template - void JUCE_VECTOR_CALLTYPE replaceWithProductOfInternal (AudioBlock src, SampleType value) const noexcept + void JUCE_VECTOR_CALLTYPE replaceWithProductOfInternal (AudioBlock src, NumericType value) const noexcept { jassert (numChannels == src.numChannels); auto n = static_cast (jmin (numSamples, src.numSamples) * sizeFactor); for (size_t ch = 0; ch < numChannels; ++ch) - FloatVectorOperations::multiply (getChannelPointer (ch), src.getChannelPointer (ch), value, n); + FloatVectorOperations::multiply (getDataPointer (ch), src.getDataPointer (ch), value, n); } template @@ -734,7 +741,7 @@ private: auto n = static_cast (jmin (numSamples, src1.numSamples, src2.numSamples) * sizeFactor); for (size_t ch = 0; ch < numChannels; ++ch) - FloatVectorOperations::multiply (getChannelPointer (ch), src1.getChannelPointer (ch), src2.getChannelPointer (ch), n); + FloatVectorOperations::multiply (getDataPointer (ch), src1.getDataPointer (ch), src2.getDataPointer (ch), n); } template @@ -751,7 +758,7 @@ private: const auto scaler = value.getNextValue(); for (size_t ch = 0; ch < numChannels; ++ch) - getChannelPointer (ch)[i] *= scaler; + getDataPointer (ch)[i] *= scaler; } } } @@ -774,20 +781,20 @@ private: const auto scaler = value.getNextValue(); for (size_t ch = 0; ch < numChannels; ++ch) - getChannelPointer (ch)[i] = scaler * src.getChannelPointer (ch)[i]; + getDataPointer (ch)[i] = scaler * src.getChannelPointer (ch)[i]; } } } //============================================================================== template - void JUCE_VECTOR_CALLTYPE addProductOfInternal (AudioBlock src, SampleType factor) const noexcept + void JUCE_VECTOR_CALLTYPE addProductOfInternal (AudioBlock src, NumericType factor) const noexcept { jassert (numChannels == src.numChannels); auto n = static_cast (jmin (numSamples, src.numSamples) * sizeFactor); for (size_t ch = 0; ch < numChannels; ++ch) - FloatVectorOperations::addWithMultiply (getChannelPointer (ch), src.getChannelPointer (ch), factor, n); + FloatVectorOperations::addWithMultiply (getDataPointer (ch), src.getDataPointer (ch), factor, n); } template @@ -797,13 +804,13 @@ private: auto n = static_cast (jmin (numSamples, src1.numSamples, src2.numSamples) * sizeFactor); for (size_t ch = 0; ch < numChannels; ++ch) - FloatVectorOperations::addWithMultiply (getChannelPointer (ch), src1.getChannelPointer (ch), src2.getChannelPointer (ch), n); + FloatVectorOperations::addWithMultiply (getDataPointer (ch), src1.getDataPointer (ch), src2.getDataPointer (ch), n); } //============================================================================== constexpr void negateInternal() const noexcept { - multiplyByInternal (static_cast (-1.0)); + multiplyByInternal (static_cast (-1.0)); } template @@ -813,7 +820,7 @@ private: auto n = static_cast (jmin (numSamples, src.numSamples) * sizeFactor); for (size_t ch = 0; ch < numChannels; ++ch) - FloatVectorOperations::negate (getChannelPointer (ch), src.getChannelPointer (ch), n); + FloatVectorOperations::negate (getDataPointer (ch), src.getDataPointer (ch), n); } template @@ -823,7 +830,7 @@ private: auto n = static_cast (jmin (numSamples, src.numSamples) * sizeFactor); for (size_t ch = 0; ch < numChannels; ++ch) - FloatVectorOperations::abs (getChannelPointer (ch), src.getChannelPointer (ch), n); + FloatVectorOperations::abs (getDataPointer (ch), src.getDataPointer (ch), n); } //============================================================================== @@ -834,7 +841,7 @@ private: auto n = static_cast (jmin (src1.numSamples, src2.numSamples, numSamples) * sizeFactor); for (size_t ch = 0; ch < numChannels; ++ch) - FloatVectorOperations::min (getChannelPointer (ch), src1.getChannelPointer (ch), src2.getChannelPointer (ch), n); + FloatVectorOperations::min (getDataPointer (ch), src1.getDataPointer (ch), src2.getDataPointer (ch), n); } template @@ -844,7 +851,7 @@ private: auto n = static_cast (jmin (src1.numSamples, src2.numSamples, numSamples) * sizeFactor); for (size_t ch = 0; ch < numChannels; ++ch) - FloatVectorOperations::max (getChannelPointer (ch), src1.getChannelPointer (ch), src2.getChannelPointer (ch), n); + FloatVectorOperations::max (getDataPointer (ch), src1.getDataPointer (ch), src2.getDataPointer (ch), n); } //============================================================================== diff --git a/modules/juce_dsp/containers/juce_AudioBlock_test.cpp b/modules/juce_dsp/containers/juce_AudioBlock_test.cpp index f0192e8a..ce86f05f 100644 --- a/modules/juce_dsp/containers/juce_AudioBlock_test.cpp +++ b/modules/juce_dsp/containers/juce_AudioBlock_test.cpp @@ -29,12 +29,32 @@ namespace juce namespace dsp { +template class AudioBlockUnitTests : public UnitTest { public: + //============================================================================== + using NumericType = typename SampleTypeHelpers::ElementType::Type; + AudioBlockUnitTests() : UnitTest ("AudioBlock", UnitTestCategories::dsp) - {} + { + for (auto v : { &data, &otherData }) + for (auto& channel : *v) + channel = allocateAlignedMemory (numSamples); + + block = { data.data(), data.size(), (size_t) numSamples }; + otherBlock = { otherData.data(), otherData.size(), (size_t) numSamples }; + + resetBlocks(); + } + + ~AudioBlockUnitTests() override + { + for (auto v : { &data, &otherData }) + for (auto channel : *v) + deallocateAlignedMemory (channel); + } void runTest() override { @@ -46,13 +66,13 @@ public: beginTest ("Constructors"); { - expect (block == AudioBlock (data.getArrayOfWritePointers(), (size_t) data.getNumChannels(), (size_t) data.getNumSamples())); - expect (block == AudioBlock (data.getArrayOfWritePointers(), (size_t) data.getNumChannels(), (size_t) 0, (size_t) data.getNumSamples())); - expect (block == AudioBlock (block)); + expect (block == AudioBlock (data.data(), data.size(), numSamples)); + expect (block == AudioBlock (data.data(), data.size(), (size_t) 0, numSamples)); + expect (block == AudioBlock (block)); - expect (block == AudioBlock (data.getArrayOfWritePointers(), (size_t) data.getNumChannels(), (size_t) data.getNumSamples())); - expect (block == AudioBlock (data.getArrayOfWritePointers(), (size_t) data.getNumChannels(), (size_t) 0, (size_t) data.getNumSamples())); - expect (block == AudioBlock (block)); + expect (block == AudioBlock (data.data(), data.size(), numSamples)); + expect (block == AudioBlock (data.data(), data.size(), (size_t) 0, numSamples)); + expect (block == AudioBlock (block)); } beginTest ("Swap"); @@ -60,188 +80,159 @@ public: resetBlocks(); expect (block != otherBlock); - expectEquals (block.getSample (0, 0), 1.0f); - expectEquals (block.getSample (0, 4), 5.0f); - expectEquals (otherBlock.getSample (0, 0), -1.0f); - expectEquals (otherBlock.getSample (0, 3), -4.0f); + expect (block.getSample (0, 0) == SampleType (1.0)); + expect (block.getSample (0, 4) == SampleType (5.0)); + expect (otherBlock.getSample (0, 0) == SampleType (-1.0)); + expect (otherBlock.getSample (0, 3) == SampleType (-4.0)); block.swap (otherBlock); expect (block != otherBlock); - expectEquals (otherBlock.getSample (0, 0), 1.0f); - expectEquals (otherBlock.getSample (0, 4), 5.0f); - expectEquals (block.getSample (0, 0), -1.0f); - expectEquals (block.getSample (0, 3), -4.0f); + expect (otherBlock.getSample (0, 0) == SampleType (1.0)); + expect (otherBlock.getSample (0, 4) == SampleType (5.0)); + expect (block.getSample (0, 0) == SampleType (-1.0)); + expect (block.getSample (0, 3) == SampleType (-4.0)); + + block.swap (otherBlock); + + expect (block.getSample (0, 0) == SampleType (1.0)); + expect (block.getSample (0, 4) == SampleType (5.0)); + expect (otherBlock.getSample (0, 0) == SampleType (-1.0)); + expect (otherBlock.getSample (0, 3) == SampleType (-4.0)); } beginTest ("Getters and setters"); { resetBlocks(); - expectEquals ((int) block.getNumChannels(), data.getNumChannels()); - expectEquals ((int) block.getNumSamples(), data.getNumSamples()); + expectEquals ((int) block.getNumChannels(), (int) data.size()); + expectEquals ((int) block.getNumSamples(), numSamples); - expectEquals (block.getChannelPointer (0)[2], 3.0f); - block.getChannelPointer (0)[2] = 999.0f; - expectEquals (block.getChannelPointer (0)[2], 999.0f); + expect (block.getChannelPointer (0)[2] == SampleType (3.0)); + block.getChannelPointer (0)[2] = SampleType (999.0); + expect (block.getChannelPointer (0)[2] == SampleType (999.0)); - expectEquals (block.getSample (0, 4), 5.0f); - expectEquals (block.getSample (1, 4), 11.0f); + expect (block.getSample (0, 4) == SampleType (5.0)); + expect (block.getSample (1, 4) == SampleType (11.0)); - expectEquals (block.getSingleChannelBlock (1).getSample (0, 3), block.getSample (1, 3)); + expect (block.getSingleChannelBlock (1).getSample (0, 3) == block.getSample (1, 3)); - expectEquals (block.getSubsetChannelBlock (0, 2).getSample (1, 3), block.getSample (1, 3)); - expectEquals (block.getSubsetChannelBlock (1, 1).getSample (0, 3), block.getSample (1, 3)); + expect (block.getSubsetChannelBlock (0, 2).getSample (1, 3) == block.getSample (1, 3)); + expect (block.getSubsetChannelBlock (1, 1).getSample (0, 3) == block.getSample (1, 3)); - block.setSample (1, 1, 777.0f); - expectEquals (block.getSample (1, 1), 777.0f); + block.setSample (1, 1, SampleType (777.0)); + expect (block.getSample (1, 1) == SampleType (777.0)); - block.addSample (1, 1, 1.0f); - expectEquals (block.getSample (1, 1), 778.0f); + block.addSample (1, 1, SampleType (1.0)); + expect (block.getSample (1, 1) == SampleType (778.0)); } - beginTest ("Copying"); + beginTest ("Basic copying"); { block.clear(); - expectEquals (block.getSample (0, 2), 0.0f); - expectEquals (block.getSample (1, 4), 0.0f); + expect (block.getSample (0, 2) == SampleType (0.0)); + expect (block.getSample (1, 4) == SampleType (0.0)); - block.fill (456.0f); - expectEquals (block.getSample (0, 2), 456.0f); - expectEquals (block.getSample (1, 4), 456.0f); + block.fill ((NumericType) 456.0); + expect (block.getSample (0, 2) == SampleType (456.0)); + expect (block.getSample (1, 4) == SampleType (456.0)); block.copyFrom (otherBlock); expect (block != otherBlock); - expectEquals (block.getSample (0, 2), otherBlock.getSample (0, 2)); - expectEquals (block.getSample (1, 4), otherBlock.getSample (1, 4)); + expect (block.getSample (0, 2) == otherBlock.getSample (0, 2)); + expect (block.getSample (1, 4) == otherBlock.getSample (1, 4)); resetBlocks(); - AudioBuffer otherBuffer ((int) block.getNumChannels(), (int) block.getNumSamples()); - otherBlock.copyTo (otherBuffer); - expectEquals (otherBlock.getSample (0, 2), otherBuffer.getSample (0, 2)); - expectEquals (otherBlock.getSample (1, 4), otherBuffer.getSample (1, 4)); - - block.copyFrom (otherBuffer); - expectEquals (block.getSample (0, 2), otherBlock.getSample (0, 2)); - expectEquals (block.getSample (1, 4), otherBlock.getSample (1, 4)); - - float testSample1 = block.getSample (0, 2); - float testSample2 = block.getSample (1, 3); + SampleType testSample1 = block.getSample (0, 2); + SampleType testSample2 = block.getSample (1, 3); expect (testSample1 != block.getSample (0, 4)); expect (testSample2 != block.getSample (1, 5)); block.move (0, 2); - expectEquals (block.getSample (0, 4), testSample1); - expectEquals (block.getSample (1, 5), testSample2); + expect (block.getSample (0, 4) == testSample1); + expect (block.getSample (1, 5) == testSample2); } beginTest ("Addition"); { resetBlocks(); - block.add (15.0f); - expectEquals (block.getSample (0, 4), 20.0f); - expectEquals (block.getSample (1, 4), 26.0f); + block.add ((NumericType) 15.0); + expect (block.getSample (0, 4) == SampleType (20.0)); + expect (block.getSample (1, 4) == SampleType (26.0)); block.add (otherBlock); - expectEquals (block.getSample (0, 4), 15.0f); - expectEquals (block.getSample (1, 4), 15.0f); + expect (block.getSample (0, 4) == SampleType (15.0)); + expect (block.getSample (1, 4) == SampleType (15.0)); - block.replaceWithSumOf (otherBlock, 9.0f); - expectEquals (block.getSample (0, 4), 4.0f); - expectEquals (block.getSample (1, 4), -2.0f); + block.replaceWithSumOf (otherBlock, (NumericType) 9.0); + expect (block.getSample (0, 4) == SampleType (4.0)); + expect (block.getSample (1, 4) == SampleType (-2.0)); resetBlocks(); block.replaceWithSumOf (block, otherBlock); - expectEquals (block.getSample (0, 4), 0.0f); - expectEquals (block.getSample (1, 4), 0.0f); + expect (block.getSample (0, 4) == SampleType (0.0)); + expect (block.getSample (1, 4) == SampleType (0.0)); } beginTest ("Subtraction"); { resetBlocks(); - block.subtract (15.0f); - expectEquals (block.getSample (0, 4), -10.0f); - expectEquals (block.getSample (1, 4), -4.0f); + block.subtract ((NumericType) 15.0); + expect (block.getSample (0, 4) == SampleType (-10.0)); + expect (block.getSample (1, 4) == SampleType (-4.0)); block.subtract (otherBlock); - expectEquals (block.getSample (0, 4), -5.0f); - expectEquals (block.getSample (1, 4), 7.0f); + expect (block.getSample (0, 4) == SampleType (-5.0)); + expect (block.getSample (1, 4) == SampleType (7.0)); - block.replaceWithDifferenceOf (otherBlock, 9.0f); - expectEquals (block.getSample (0, 4), -14.0f); - expectEquals (block.getSample (1, 4), -20.0f); + block.replaceWithDifferenceOf (otherBlock, (NumericType) 9.0); + expect (block.getSample (0, 4) == SampleType (-14.0)); + expect (block.getSample (1, 4) == SampleType (-20.0)); resetBlocks(); block.replaceWithDifferenceOf (block, otherBlock); - expectEquals (block.getSample (0, 4), 10.0f); - expectEquals (block.getSample (1, 4), 22.0f); + expect (block.getSample (0, 4) == SampleType (10.0)); + expect (block.getSample (1, 4) == SampleType (22.0)); } beginTest ("Multiplication"); { resetBlocks(); - block.multiplyBy (10.0f); - expectEquals (block.getSample (0, 4), 50.0f); - expectEquals (block.getSample (1, 4), 110.0f); + block.multiplyBy ((NumericType) 10.0); + expect (block.getSample (0, 4) == SampleType (50.0)); + expect (block.getSample (1, 4) == SampleType (110.0)); block.multiplyBy (otherBlock); - expectEquals (block.getSample (0, 4), -250.0f); - expectEquals (block.getSample (1, 4), -1210.0f); + expect (block.getSample (0, 4) == SampleType (-250.0)); + expect (block.getSample (1, 4) == SampleType (-1210.0)); - block.replaceWithProductOf (otherBlock, 3.0f); - expectEquals (block.getSample (0, 4), -15.0f); - expectEquals (block.getSample (1, 4), -33.0f); + block.replaceWithProductOf (otherBlock, (NumericType) 3.0); + expect (block.getSample (0, 4) == SampleType (-15.0)); + expect (block.getSample (1, 4) == SampleType (-33.0)); resetBlocks(); block.replaceWithProductOf (block, otherBlock); - expectEquals (block.getSample (0, 4), -25.0f); - expectEquals (block.getSample (1, 4), -121.0f); - } - - beginTest ("Smoothing"); - { - block.fill (1.0f); - SmoothedValue sv { 1.0f }; - sv.reset (1, 4); - sv.setTargetValue (0.0f); - - block.multiplyBy (sv); - expect (block.getSample (0, 2) < 1.0f); - expect (block.getSample (1, 2) < 1.0f); - expect (block.getSample (0, 2) > 0.0f); - expect (block.getSample (1, 2) > 0.0f); - expectEquals (block.getSample (0, 5), 0.0f); - expectEquals (block.getSample (1, 5), 0.0f); - - sv.setCurrentAndTargetValue (-1.0f); - sv.setTargetValue (0.0f); - otherBlock.fill (-1.0f); - block.replaceWithProductOf (otherBlock, sv); - expect (block.getSample (0, 2) < 1.0f); - expect (block.getSample (1, 2) < 1.0f); - expect (block.getSample (0, 2) > 0.0f); - expect (block.getSample (1, 2) > 0.0f); - expectEquals (block.getSample (0, 5), 0.0f); - expectEquals (block.getSample (1, 5), 0.0f); + expect (block.getSample (0, 4) == SampleType (-25.0)); + expect (block.getSample (1, 4) == SampleType (-121.0)); } beginTest ("Multiply add"); { resetBlocks(); - block.addProductOf (otherBlock, -1.0f); - expectEquals (block.getSample (0, 4), 10.0f); - expectEquals (block.getSample (1, 4), 22.0f); + block.addProductOf (otherBlock, (NumericType) -1.0); + expect (block.getSample (0, 4) == SampleType (10.0)); + expect (block.getSample (1, 4) == SampleType (22.0)); block.addProductOf (otherBlock, otherBlock); - expectEquals (block.getSample (0, 4), 35.0f); - expectEquals (block.getSample (1, 4), 143.0f); + expect (block.getSample (0, 4) == SampleType (35.0)); + expect (block.getSample (1, 4) == SampleType (143.0)); } beginTest ("Negative abs min max"); @@ -250,93 +241,259 @@ public: otherBlock.negate(); block.add (otherBlock); - expectEquals (block.getSample (0, 4), 10.0f); - expectEquals (block.getSample (1, 4), 22.0f); + expect (block.getSample (0, 4) == SampleType (10.0)); + expect (block.getSample (1, 4) == SampleType (22.0)); block.replaceWithNegativeOf (otherBlock); - expectEquals (block.getSample (0, 4), -5.0f); - expectEquals (block.getSample (1, 4), -11.0f); + expect (block.getSample (0, 4) == SampleType (-5.0)); + expect (block.getSample (1, 4) == SampleType (-11.0)); block.clear(); otherBlock.negate(); block.replaceWithAbsoluteValueOf (otherBlock); - expectEquals (block.getSample (0, 4), 5.0f); - expectEquals (block.getSample (1, 4), 11.0f); + expect (block.getSample (0, 4) == SampleType (5.0)); + expect (block.getSample (1, 4) == SampleType (11.0)); resetBlocks(); block.replaceWithMinOf (block, otherBlock); - expectEquals (block.getSample (0, 4), -5.0f); - expectEquals (block.getSample (1, 4), -11.0f); + expect (block.getSample (0, 4) == SampleType (-5.0)); + expect (block.getSample (1, 4) == SampleType (-11.0)); resetBlocks(); block.replaceWithMaxOf (block, otherBlock); - expectEquals (block.getSample (0, 4), 5.0f); - expectEquals (block.getSample (1, 4), 11.0f); + expect (block.getSample (0, 4) == SampleType (5.0)); + expect (block.getSample (1, 4) == SampleType (11.0)); resetBlocks(); auto range = block.findMinAndMax(); - expectEquals (range.getStart(), 1.0f); - expectEquals (range.getEnd(), 12.0f); + expect (SampleType (range.getStart()) == SampleType (1.0)); + expect (SampleType (range.getEnd()) == SampleType (12.0)); } beginTest ("Operators"); { resetBlocks(); - block += 10.0f; - expectEquals (block.getSample (0, 4), 15.0f); - expectEquals (block.getSample (1, 4), 21.0f); + block += (NumericType) 10.0; + expect (block.getSample (0, 4) == SampleType (15.0)); + expect (block.getSample (1, 4) == SampleType (21.0)); block += otherBlock; - expectEquals (block.getSample (0, 4), 10.0f); - expectEquals (block.getSample (1, 4), 10.0f); + expect (block.getSample (0, 4) == SampleType (10.0)); + expect (block.getSample (1, 4) == SampleType (10.0)); resetBlocks(); - block -= 10.0f; - expectEquals (block.getSample (0, 4), -5.0f); - expectEquals (block.getSample (1, 4), 1.0f); + block -= (NumericType) 10.0; + expect (block.getSample (0, 4) == SampleType (-5.0)); + expect (block.getSample (1, 4) == SampleType (1.0)); block -= otherBlock; - expectEquals (block.getSample (0, 4), 0.0f); - expectEquals (block.getSample (1, 4), 12.0f); + expect (block.getSample (0, 4) == SampleType (0.0)); + expect (block.getSample (1, 4) == SampleType (12.0)); resetBlocks(); - block *= 10.0f; - expectEquals (block.getSample (0, 4), 50.0f); - expectEquals (block.getSample (1, 4), 110.0f); + block *= (NumericType) 10.0; + expect (block.getSample (0, 4) == SampleType (50.0)); + expect (block.getSample (1, 4) == SampleType (110.0)); block *= otherBlock; - expectEquals (block.getSample (0, 4), -250.0f); - expectEquals (block.getSample (1, 4), -1210.0f); + expect (block.getSample (0, 4) == SampleType (-250.0)); + expect (block.getSample (1, 4) == SampleType (-1210.0)); } beginTest ("Process"); { resetBlocks(); - AudioBlock::process (block, otherBlock, [](float x) { return x + 1.0f; }); - expectEquals (otherBlock.getSample (0, 4), 6.0f); - expectEquals (otherBlock.getSample (1, 4), 12.0f); + AudioBlock::process (block, otherBlock, [](SampleType x) { return x + (NumericType) 1.0; }); + expect (otherBlock.getSample (0, 4) == SampleType (6.0)); + expect (otherBlock.getSample (1, 4) == SampleType (12.0)); + } + + beginTest ("Copying"); + { + resetBlocks(); + copyingTests(); + } + + beginTest ("Smoothing"); + { + resetBlocks(); + smoothedValueTests(); } } private: - AudioBuffer data { 2, 6 }, otherData { 2, 6 }; - AudioBlock block { data }, otherBlock { otherData }; + //============================================================================== + template + using ScalarVoid = typename std::enable_if_t < std::is_scalar ::value, void>; + + template + using SIMDVoid = typename std::enable_if_t ::value, void>; + + //============================================================================== + template + ScalarVoid copyingTests() + { + auto unchangedElement1 = block.getSample (0, 4); + auto unchangedElement2 = block.getSample (1, 1); + + AudioBuffer otherBuffer (otherData.data(), (int) otherData.size(), numSamples); + + block.copyFrom (otherBuffer, 1, 2, 2); + + expectEquals (block.getSample (0, 4), unchangedElement1); + expectEquals (block.getSample (1, 1), unchangedElement2); + expectEquals (block.getSample (0, 2), otherBuffer.getSample (0, 1)); + expectEquals (block.getSample (1, 3), otherBuffer.getSample (1, 2)); + resetBlocks(); + + unchangedElement1 = otherBuffer.getSample (0, 4); + unchangedElement2 = otherBuffer.getSample (1, 3); + + block.copyTo (otherBuffer, 2, 1, 2); + + expectEquals (otherBuffer.getSample (0, 4), unchangedElement1); + expectEquals (otherBuffer.getSample (1, 3), unchangedElement2); + expectEquals (otherBuffer.getSample (0, 1), block.getSample (0, 2)); + expectEquals (otherBuffer.getSample (1, 2), block.getSample (1, 3)); + } + + template + SIMDVoid copyingTests() + { + auto numSIMDElements = SIMDRegister::SIMDNumElements; + AudioBuffer numericData ((int) block.getNumChannels(), + (int) (block.getNumSamples() * numSIMDElements)); + + for (int c = 0; c < numericData.getNumChannels(); ++c) + std::fill_n (numericData.getWritePointer (c), numericData.getNumSamples(), (NumericType) 1.0); + + numericData.applyGainRamp (0, numericData.getNumSamples(), (NumericType) 0.127, (NumericType) 17.3); + + auto lastUnchangedIndexBeforeCopiedRange = (int) ((numSIMDElements * 2) - 1); + auto firstUnchangedIndexAfterCopiedRange = (int) ((numSIMDElements * 4) + 1); + auto unchangedElement1 = numericData.getSample (0, lastUnchangedIndexBeforeCopiedRange); + auto unchangedElement2 = numericData.getSample (1, firstUnchangedIndexAfterCopiedRange); + + block.copyTo (numericData, 1, 2, 2); + + expectEquals (numericData.getSample (0, lastUnchangedIndexBeforeCopiedRange), unchangedElement1); + expectEquals (numericData.getSample (1, firstUnchangedIndexAfterCopiedRange), unchangedElement2); + expect (SampleType (numericData.getSample (0, 2 * (int) numSIMDElements)) == block.getSample (0, 1)); + expect (SampleType (numericData.getSample (1, 3 * (int) numSIMDElements)) == block.getSample (1, 2)); + + numericData.applyGainRamp (0, numericData.getNumSamples(), (NumericType) 15.1, (NumericType) 0.7); + + auto unchangedSIMDElement1 = block.getSample (0, 1); + auto unchangedSIMDElement2 = block.getSample (1, 4); + + block.copyFrom (numericData, 1, 2, 2); + + expect (block.getSample (0, 1) == unchangedSIMDElement1); + expect (block.getSample (1, 4) == unchangedSIMDElement2); + expectEquals (block.getSample (0, 2).get (0), numericData.getSample (0, (int) numSIMDElements)); + expectEquals (block.getSample (1, 3).get (0), numericData.getSample (1, (int) (numSIMDElements * 2))); + + if (numSIMDElements > 1) + { + expectEquals (block.getSample (0, 2).get (1), numericData.getSample (0, (int) (numSIMDElements + 1))); + expectEquals (block.getSample (1, 3).get (1), numericData.getSample (1, (int) ((numSIMDElements * 2) + 1))); + } + } + + //============================================================================== + template + ScalarVoid smoothedValueTests() + { + block.fill ((SampleType) 1.0); + SmoothedValue sv { (SampleType) 1.0 }; + sv.reset (1, 4); + sv.setTargetValue ((SampleType) 0.0); + + block.multiplyBy (sv); + expect (block.getSample (0, 2) < (SampleType) 1.0); + expect (block.getSample (1, 2) < (SampleType) 1.0); + expect (block.getSample (0, 2) > (SampleType) 0.0); + expect (block.getSample (1, 2) > (SampleType) 0.0); + expectEquals (block.getSample (0, 5), (SampleType) 0.0); + expectEquals (block.getSample (1, 5), (SampleType) 0.0); + + sv.setCurrentAndTargetValue (-1.0f); + sv.setTargetValue (0.0f); + otherBlock.fill (-1.0f); + block.replaceWithProductOf (otherBlock, sv); + expect (block.getSample (0, 2) < (SampleType) 1.0); + expect (block.getSample (1, 2) < (SampleType) 1.0); + expect (block.getSample (0, 2) > (SampleType) 0.0); + expect (block.getSample (1, 2) > (SampleType) 0.0); + expectEquals (block.getSample (0, 5), (SampleType) 0.0); + expectEquals (block.getSample (1, 5), (SampleType) 0.0); + } + + template + SIMDVoid smoothedValueTests() {} + + //============================================================================== void resetBlocks() { - auto value = 1.0f; + auto value = SampleType (1.0); for (size_t c = 0; c < block.getNumChannels(); ++c) { for (size_t i = 0; i < block.getNumSamples(); ++i) { block.setSample ((int) c, (int) i, value); - value += 1.0f; + value += SampleType (1.0); } } otherBlock.replaceWithNegativeOf (block); } + + //============================================================================== + static SampleType* allocateAlignedMemory (int numSamplesToAllocate) + { + auto alignmentLowerBound = std::alignment_of::value; + #if ! JUCE_WINDOWS + alignmentLowerBound = jmax (sizeof (void*), alignmentLowerBound); + #endif + auto alignmentOrder = std::ceil (std::log2 (alignmentLowerBound)); + auto requiredAlignment = (size_t) std::pow (2, alignmentOrder); + + auto size = (size_t) numSamplesToAllocate * sizeof (SampleType); + + #if JUCE_WINDOWS + auto* memory = _aligned_malloc (size, requiredAlignment); + #else + void* memory; + auto result = posix_memalign (&memory, requiredAlignment, size); + + if (result != 0) + { + jassertfalse; + return nullptr; + } + #endif + + return static_cast (memory); + } + + void deallocateAlignedMemory (void* address) + { + #if JUCE_WINDOWS + _aligned_free (address); + #else + free (address); + #endif + } + + //============================================================================== + static constexpr int numChannels = 2, numSamples = 6; + std::array data, otherData; + AudioBlock block, otherBlock; }; -static AudioBlockUnitTests audioBlockUnitTests; +static AudioBlockUnitTests audioBlockFloatUnitTests; +static AudioBlockUnitTests audioBlockDoubleUnitTests; +static AudioBlockUnitTests> audioBlockSIMDFloatUnitTests; +static AudioBlockUnitTests> audioBlockSIMDDoubleUnitTests; } // namespace dsp } // namespace juce diff --git a/modules/juce_dsp/containers/juce_SIMDRegister.h b/modules/juce_dsp/containers/juce_SIMDRegister.h index a74860fb..9cf82588 100644 --- a/modules/juce_dsp/containers/juce_SIMDRegister.h +++ b/modules/juce_dsp/containers/juce_SIMDRegister.h @@ -40,7 +40,7 @@ namespace dsp A wrapper around the platform's native SIMD register type. This class is only available on SIMD machines. Use JUCE_USE_SIMD to query - if SIMD is avaialble for your system. + if SIMD is available for your system. SIMDRegister is a templated class representing the native vectorized version of FloatingType. SIMDRegister supports all numerical @@ -117,7 +117,7 @@ struct SIMDRegister /** Constructs an object from a scalar type by broadcasting it to all elements. */ inline SIMDRegister (Type s) noexcept { *this = s; } - /** Destrutor. */ + /** Destructor. */ inline ~SIMDRegister() noexcept = default; //============================================================================== @@ -204,23 +204,23 @@ struct SIMDRegister inline SIMDRegister& JUCE_VECTOR_CALLTYPE operator*= (ElementType s) noexcept { value = CmplxOps::mul (value, CmplxOps::expand (s)); return *this; } //============================================================================== - /** Bit-and the reciver with SIMDRegister v and store the result in the receiver. */ + /** Bit-and the receiver with SIMDRegister v and store the result in the receiver. */ inline SIMDRegister& JUCE_VECTOR_CALLTYPE operator&= (vMaskType v) noexcept { value = NativeOps::bit_and (value, toVecType (v.value)); return *this; } - /** Bit-or the reciver with SIMDRegister v and store the result in the receiver. */ + /** Bit-or the receiver with SIMDRegister v and store the result in the receiver. */ inline SIMDRegister& JUCE_VECTOR_CALLTYPE operator|= (vMaskType v) noexcept { value = NativeOps::bit_or (value, toVecType (v.value)); return *this; } - /** Bit-xor the reciver with SIMDRegister v and store the result in the receiver. */ + /** Bit-xor the receiver with SIMDRegister v and store the result in the receiver. */ inline SIMDRegister& JUCE_VECTOR_CALLTYPE operator^= (vMaskType v) noexcept { value = NativeOps::bit_xor (value, toVecType (v.value)); return *this; } //============================================================================== - /** Bit-and each element of the reciver with the scalar s and store the result in the receiver.*/ + /** Bit-and each element of the receiver with the scalar s and store the result in the receiver.*/ inline SIMDRegister& JUCE_VECTOR_CALLTYPE operator&= (MaskType s) noexcept { value = NativeOps::bit_and (value, toVecType (s)); return *this; } - /** Bit-or each element of the reciver with the scalar s and store the result in the receiver.*/ + /** Bit-or each element of the receiver with the scalar s and store the result in the receiver.*/ inline SIMDRegister& JUCE_VECTOR_CALLTYPE operator|= (MaskType s) noexcept { value = NativeOps::bit_or (value, toVecType (s)); return *this; } - /** Bit-xor each element of the reciver with the scalar s and store the result in the receiver.*/ + /** Bit-xor each element of the receiver with the scalar s and store the result in the receiver.*/ inline SIMDRegister& JUCE_VECTOR_CALLTYPE operator^= (MaskType s) noexcept { value = NativeOps::bit_xor (value, toVecType (s)); return *this; } //============================================================================== @@ -267,10 +267,10 @@ struct SIMDRegister inline SIMDRegister JUCE_VECTOR_CALLTYPE operator^ (MaskType s) const noexcept { return { NativeOps::bit_xor (value, toVecType (s)) }; } //============================================================================== - /** Returns true if all elements-wise comparisons return true. */ + /** Returns true if all element-wise comparisons return true. */ inline bool JUCE_VECTOR_CALLTYPE operator== (SIMDRegister other) const noexcept { return NativeOps::allEqual (value, other.value); } - /** Returns true if any elements-wise comparisons return false. */ + /** Returns true if any element-wise comparisons return false. */ inline bool JUCE_VECTOR_CALLTYPE operator!= (SIMDRegister other) const noexcept { return ! (*this == other); } /** Returns true if all elements are equal to the scalar. */ diff --git a/modules/juce_dsp/containers/juce_SIMDRegister_test.cpp b/modules/juce_dsp/containers/juce_SIMDRegister_test.cpp index 837d586f..ea2b4fa9 100644 --- a/modules/juce_dsp/containers/juce_SIMDRegister_test.cpp +++ b/modules/juce_dsp/containers/juce_SIMDRegister_test.cpp @@ -195,7 +195,7 @@ public: } //============================================================================== - // Someuseful operations to test + // Some useful operations to test struct Addition { template diff --git a/modules/juce_dsp/frequency/juce_FFT.h b/modules/juce_dsp/frequency/juce_FFT.h index c2669cfd..883af17b 100644 --- a/modules/juce_dsp/frequency/juce_FFT.h +++ b/modules/juce_dsp/frequency/juce_FFT.h @@ -62,7 +62,7 @@ public: /** Performs an in-place forward transform on a block of real data. - As the coefficients of the negative frequences (frequencies higher than + As the coefficients of the negative frequencies (frequencies higher than N/2 or pi) are the complex conjugate of their positive counterparts, it may not be necessary to calculate them for your particular application. You can use dontCalculateNegativeFrequencies to let the FFT diff --git a/modules/juce_dsp/juce_dsp.h b/modules/juce_dsp/juce_dsp.h index 68abb03e..515fc153 100644 --- a/modules/juce_dsp/juce_dsp.h +++ b/modules/juce_dsp/juce_dsp.h @@ -36,7 +36,7 @@ ID: juce_dsp vendor: juce - version: 5.4.5 + version: 5.4.6 name: JUCE DSP classes description: Classes for audio buffer manipulation, digital audio processing, filtering, oversampling, fast math functions etc. website: http://www.juce.com/juce diff --git a/modules/juce_dsp/maths/juce_Matrix.h b/modules/juce_dsp/maths/juce_Matrix.h index 8aa109d1..ba33d7a7 100644 --- a/modules/juce_dsp/maths/juce_Matrix.h +++ b/modules/juce_dsp/maths/juce_Matrix.h @@ -198,7 +198,7 @@ public: with the coefficients of b. After the execution of the algorithm, the vector b will contain the solution. - Returns true if the linear system of euqations was successfully solved. + Returns true if the linear system of equations was successfully solved. */ bool solve (Matrix& b) const noexcept; diff --git a/modules/juce_dsp/processors/juce_LadderFilter.h b/modules/juce_dsp/processors/juce_LadderFilter.h index f3f302d4..7b2e7a8a 100644 --- a/modules/juce_dsp/processors/juce_LadderFilter.h +++ b/modules/juce_dsp/processors/juce_LadderFilter.h @@ -73,7 +73,7 @@ public: @param newValue a value between 0 and 1; higher values increase the resonance and can result in self oscillation! */ void setResonance (Type newValue) noexcept; - /** Sets the amound of saturation in the filter. + /** Sets the amount of saturation in the filter. @param newValue saturation amount; it can be any number greater than or equal to one. Higher values result in more distortion.*/ void setDrive (Type newValue) noexcept; diff --git a/modules/juce_dsp/processors/juce_Oscillator.h b/modules/juce_dsp/processors/juce_Oscillator.h index 41b65d56..c3bb2da3 100644 --- a/modules/juce_dsp/processors/juce_Oscillator.h +++ b/modules/juce_dsp/processors/juce_Oscillator.h @@ -132,7 +132,7 @@ public: auto&& outBlock = context.getOutputBlock(); auto&& inBlock = context.getInputBlock(); - // this is an output-only processory + // this is an output-only processor jassert (outBlock.getNumSamples() <= static_cast (rampBuffer.size())); auto len = outBlock.getNumSamples(); diff --git a/modules/juce_dsp/processors/juce_Oversampling.cpp b/modules/juce_dsp/processors/juce_Oversampling.cpp index a7b1c8f6..06cc7298 100644 --- a/modules/juce_dsp/processors/juce_Oversampling.cpp +++ b/modules/juce_dsp/processors/juce_Oversampling.cpp @@ -53,13 +53,13 @@ struct Oversampling::OversamplingStage buffer.clear(); } - dsp::AudioBlock getProcessedSamples (size_t numSamples) + AudioBlock getProcessedSamples (size_t numSamples) { - return dsp::AudioBlock (buffer).getSubBlock (0, numSamples); + return AudioBlock (buffer).getSubBlock (0, numSamples); } - virtual void processSamplesUp (dsp::AudioBlock&) = 0; - virtual void processSamplesDown (dsp::AudioBlock&) = 0; + virtual void processSamplesUp (const AudioBlock&) = 0; + virtual void processSamplesDown (AudioBlock&) = 0; AudioBuffer buffer; size_t numChannels, factor; @@ -83,7 +83,7 @@ struct OversamplingDummy : public Oversampling::OversamplingStage return 0; } - void processSamplesUp (dsp::AudioBlock& inputBlock) override + void processSamplesUp (const AudioBlock& inputBlock) override { jassert (inputBlock.getNumChannels() <= static_cast (ParentType::buffer.getNumChannels())); jassert (inputBlock.getNumSamples() * ParentType::factor <= static_cast (ParentType::buffer.getNumSamples())); @@ -93,7 +93,7 @@ struct OversamplingDummy : public Oversampling::OversamplingStage inputBlock.getChannelPointer (channel), static_cast (inputBlock.getNumSamples())); } - void processSamplesDown (dsp::AudioBlock& outputBlock) override + void processSamplesDown (AudioBlock& outputBlock) override { jassert (outputBlock.getNumChannels() <= static_cast (ParentType::buffer.getNumChannels())); jassert (outputBlock.getNumSamples() * ParentType::factor <= static_cast (ParentType::buffer.getNumSamples())); @@ -122,8 +122,8 @@ struct Oversampling2TimesEquirippleFIR : public Oversampling::Overs SampleType stopbandAmplitudedBDown) : ParentType (numChans, 2) { - coefficientsUp = *dsp::FilterDesign::designFIRLowpassHalfBandEquirippleMethod (normalisedTransitionWidthUp, stopbandAmplitudedBUp); - coefficientsDown = *dsp::FilterDesign::designFIRLowpassHalfBandEquirippleMethod (normalisedTransitionWidthDown, stopbandAmplitudedBDown); + coefficientsUp = *FilterDesign::designFIRLowpassHalfBandEquirippleMethod (normalisedTransitionWidthUp, stopbandAmplitudedBUp); + coefficientsDown = *FilterDesign::designFIRLowpassHalfBandEquirippleMethod (normalisedTransitionWidthDown, stopbandAmplitudedBDown); auto N = coefficientsUp.getFilterOrder() + 1; stateUp.setSize (static_cast (this->numChannels), static_cast (N)); @@ -155,7 +155,7 @@ struct Oversampling2TimesEquirippleFIR : public Oversampling::Overs position.fill (0); } - void processSamplesUp (dsp::AudioBlock& inputBlock) override + void processSamplesUp (const AudioBlock& inputBlock) override { jassert (inputBlock.getNumChannels() <= static_cast (ParentType::buffer.getNumChannels())); jassert (inputBlock.getNumSamples() * ParentType::factor <= static_cast (ParentType::buffer.getNumSamples())); @@ -195,7 +195,7 @@ struct Oversampling2TimesEquirippleFIR : public Oversampling::Overs } } - void processSamplesDown (dsp::AudioBlock& outputBlock) override + void processSamplesDown (AudioBlock& outputBlock) override { jassert (outputBlock.getNumChannels() <= static_cast (ParentType::buffer.getNumChannels())); jassert (outputBlock.getNumSamples() * ParentType::factor <= static_cast (ParentType::buffer.getNumSamples())); @@ -248,7 +248,7 @@ struct Oversampling2TimesEquirippleFIR : public Oversampling::Overs private: //============================================================================== - dsp::FIR::Coefficients coefficientsUp, coefficientsDown; + FIR::Coefficients coefficientsUp, coefficientsDown; AudioBuffer stateUp, stateDown, stateDown2; Array position; @@ -274,11 +274,11 @@ struct Oversampling2TimesPolyphaseIIR : public Oversampling::Oversa SampleType stopbandAmplitudedBDown) : ParentType (numChans, 2) { - auto structureUp = dsp::FilterDesign::designIIRLowpassHalfBandPolyphaseAllpassMethod (normalisedTransitionWidthUp, stopbandAmplitudedBUp); + auto structureUp = FilterDesign::designIIRLowpassHalfBandPolyphaseAllpassMethod (normalisedTransitionWidthUp, stopbandAmplitudedBUp); auto coeffsUp = getCoefficients (structureUp); latency = static_cast (-(coeffsUp.getPhaseForFrequency (0.0001, 1.0)) / (0.0001 * MathConstants::twoPi)); - auto structureDown = dsp::FilterDesign::designIIRLowpassHalfBandPolyphaseAllpassMethod (normalisedTransitionWidthDown, stopbandAmplitudedBDown); + auto structureDown = FilterDesign::designIIRLowpassHalfBandPolyphaseAllpassMethod (normalisedTransitionWidthDown, stopbandAmplitudedBDown); auto coeffsDown = getCoefficients (structureDown); latency += static_cast (-(coeffsDown.getPhaseForFrequency (0.0001, 1.0)) / (0.0001 * MathConstants::twoPi)); @@ -313,7 +313,7 @@ struct Oversampling2TimesPolyphaseIIR : public Oversampling::Oversa delayDown.fill (0); } - void processSamplesUp (dsp::AudioBlock& inputBlock) override + void processSamplesUp (const AudioBlock& inputBlock) override { jassert (inputBlock.getNumChannels() <= static_cast (ParentType::buffer.getNumChannels())); jassert (inputBlock.getNumSamples() * ParentType::factor <= static_cast (ParentType::buffer.getNumSamples())); @@ -368,7 +368,7 @@ struct Oversampling2TimesPolyphaseIIR : public Oversampling::Oversa snapToZero (true); } - void processSamplesDown (dsp::AudioBlock& outputBlock) override + void processSamplesDown (AudioBlock& outputBlock) override { jassert (outputBlock.getNumChannels() <= static_cast (ParentType::buffer.getNumChannels())); jassert (outputBlock.getNumSamples() * ParentType::factor <= static_cast (ParentType::buffer.getNumSamples())); @@ -457,12 +457,12 @@ private: /** This function calculates the equivalent high order IIR filter of a given polyphase cascaded allpass filters structure. */ - dsp::IIR::Coefficients getCoefficients (typename dsp::FilterDesign::IIRPolyphaseAllpassStructure& structure) const + IIR::Coefficients getCoefficients (typename FilterDesign::IIRPolyphaseAllpassStructure& structure) const { constexpr auto one = static_cast (1.0); - dsp::Polynomial numerator1 ({ one }), denominator1 ({ one }), - numerator2 ({ one }), denominator2 ({ one }); + Polynomial numerator1 ({ one }), denominator1 ({ one }), + numerator2 ({ one }), denominator2 ({ one }); for (auto* i : structure.directPath) { @@ -470,13 +470,13 @@ private: if (i->getFilterOrder() == 1) { - numerator1 = numerator1.getProductWith (dsp::Polynomial ({ coeffs[0], coeffs[1] })); - denominator1 = denominator1.getProductWith (dsp::Polynomial ({ one, coeffs[2] })); + numerator1 = numerator1 .getProductWith (Polynomial ({ coeffs[0], coeffs[1] })); + denominator1 = denominator1.getProductWith (Polynomial ({ one, coeffs[2] })); } else { - numerator1 = numerator1.getProductWith (dsp::Polynomial ({ coeffs[0], coeffs[1], coeffs[2] })); - denominator1 = denominator1.getProductWith (dsp::Polynomial ({ one, coeffs[3], coeffs[4] })); + numerator1 = numerator1 .getProductWith (Polynomial ({ coeffs[0], coeffs[1], coeffs[2] })); + denominator1 = denominator1.getProductWith (Polynomial ({ one, coeffs[3], coeffs[4] })); } } @@ -486,13 +486,13 @@ private: if (i->getFilterOrder() == 1) { - numerator2 = numerator2.getProductWith (dsp::Polynomial ({ coeffs[0], coeffs[1] })); - denominator2 = denominator2.getProductWith (dsp::Polynomial ({ one, coeffs[2] })); + numerator2 = numerator2 .getProductWith (Polynomial ({ coeffs[0], coeffs[1] })); + denominator2 = denominator2.getProductWith (Polynomial ({ one, coeffs[2] })); } else { - numerator2 = numerator2.getProductWith (dsp::Polynomial ({ coeffs[0], coeffs[1], coeffs[2] })); - denominator2 = denominator2.getProductWith (dsp::Polynomial ({ one, coeffs[3], coeffs[4] })); + numerator2 = numerator2 .getProductWith (Polynomial ({ coeffs[0], coeffs[1], coeffs[2] })); + denominator2 = denominator2.getProductWith (Polynomial ({ one, coeffs[3], coeffs[4] })); } } @@ -501,7 +501,7 @@ private: auto numerator = numeratorf1.getSumWith (numeratorf2); auto denominator = denominator1.getProductWith (denominator2); - dsp::IIR::Coefficients coeffs; + IIR::Coefficients coeffs; coeffs.coefficients.clear(); auto inversion = one / denominator[0]; @@ -677,26 +677,28 @@ void Oversampling::reset() noexcept } template -typename dsp::AudioBlock Oversampling::processSamplesUp (const dsp::AudioBlock& inputBlock) noexcept +AudioBlock Oversampling::processSamplesUp (const AudioBlock& inputBlock) noexcept { jassert (! stages.isEmpty()); if (! isReady) return {}; - auto audioBlock = inputBlock; + auto* firstStage = stages.getUnchecked (0); + firstStage->processSamplesUp (inputBlock); + auto block = firstStage->getProcessedSamples (inputBlock.getNumSamples() * firstStage->factor); - for (auto* stage : stages) + for (int i = 1; i < stages.size(); ++i) { - stage->processSamplesUp (audioBlock); - audioBlock = stage->getProcessedSamples (audioBlock.getNumSamples() * stage->factor); + stages[i]->processSamplesUp (block); + block = stages[i]->getProcessedSamples (block.getNumSamples() * stages[i]->factor); } - return audioBlock; + return block; } template -void Oversampling::processSamplesDown (dsp::AudioBlock& outputBlock) noexcept +void Oversampling::processSamplesDown (AudioBlock& outputBlock) noexcept { jassert (! stages.isEmpty()); diff --git a/modules/juce_dsp/processors/juce_Oversampling.h b/modules/juce_dsp/processors/juce_Oversampling.h index e4fbb9db..10c715a0 100644 --- a/modules/juce_dsp/processors/juce_Oversampling.h +++ b/modules/juce_dsp/processors/juce_Oversampling.h @@ -126,14 +126,14 @@ public: Don't forget to set the sample rate of that processing to N times the original sample rate. */ - dsp::AudioBlock processSamplesUp (const dsp::AudioBlock& inputBlock) noexcept; + AudioBlock processSamplesUp (const AudioBlock& inputBlock) noexcept; /** Must be called to perform the downsampling, after the upsampling and the non-linear processing. The output signal is probably delayed by the internal latency of the whole oversampling behaviour, so don't forget to take this into account. */ - void processSamplesDown (dsp::AudioBlock& outputBlock) noexcept; + void processSamplesDown (AudioBlock& outputBlock) noexcept; //============================================================================== /** Adds a new oversampling stage to the Oversampling class, multiplying the diff --git a/modules/juce_events/broadcasters/juce_ActionBroadcaster.cpp b/modules/juce_events/broadcasters/juce_ActionBroadcaster.cpp index 7112a811..c900c00c 100644 --- a/modules/juce_events/broadcasters/juce_ActionBroadcaster.cpp +++ b/modules/juce_events/broadcasters/juce_ActionBroadcaster.cpp @@ -51,7 +51,7 @@ private: //============================================================================== ActionBroadcaster::ActionBroadcaster() { - // are you trying to create this object before or after juce has been intialised?? + // are you trying to create this object before or after juce has been initialised?? JUCE_ASSERT_MESSAGE_MANAGER_EXISTS } diff --git a/modules/juce_events/interprocess/juce_NetworkServiceDiscovery.cpp b/modules/juce_events/interprocess/juce_NetworkServiceDiscovery.cpp index 3175ad06..f2ddcc5c 100644 --- a/modules/juce_events/interprocess/juce_NetworkServiceDiscovery.cpp +++ b/modules/juce_events/interprocess/juce_NetworkServiceDiscovery.cpp @@ -23,6 +23,11 @@ namespace juce { +#if JUCE_ANDROID + extern void acquireMulticastLock(); + extern void releaseMulticastLock(); +#endif + NetworkServiceDiscovery::Advertiser::Advertiser (const String& serviceTypeUID, const String& serviceDescription, int broadcastPortToUse, int connectionPort, @@ -73,6 +78,10 @@ void NetworkServiceDiscovery::Advertiser::sendBroadcast() NetworkServiceDiscovery::AvailableServiceList::AvailableServiceList (const String& serviceType, int broadcastPort) : Thread ("Discovery_listen"), serviceTypeUID (serviceType) { + #if JUCE_ANDROID + acquireMulticastLock(); + #endif + socket.bindToPort (broadcastPort); startThread (2); } @@ -81,6 +90,10 @@ NetworkServiceDiscovery::AvailableServiceList::~AvailableServiceList() { socket.shutdown(); stopThread (2000); + + #if JUCE_ANDROID + releaseMulticastLock(); + #endif } void NetworkServiceDiscovery::AvailableServiceList::run() diff --git a/modules/juce_events/interprocess/juce_NetworkServiceDiscovery.h b/modules/juce_events/interprocess/juce_NetworkServiceDiscovery.h index 61ac68eb..5c1fdcd8 100644 --- a/modules/juce_events/interprocess/juce_NetworkServiceDiscovery.h +++ b/modules/juce_events/interprocess/juce_NetworkServiceDiscovery.h @@ -28,6 +28,8 @@ namespace juce Contains classes that implement a simple protocol for broadcasting the availability and location of a discoverable service on the local network, and for maintaining a list of known services. + + @tags{Events} */ struct NetworkServiceDiscovery { @@ -36,6 +38,8 @@ struct NetworkServiceDiscovery To use, simply create an instance of an Advertiser and it'll broadcast until you delete it. + + @tags{Events} */ struct Advertiser : private Thread { @@ -68,7 +72,10 @@ struct NetworkServiceDiscovery //============================================================================== /** Contains information about a service that has been found on the network. + @see AvailableServiceList, Advertiser + + @tags{Events} */ struct Service { @@ -87,7 +94,10 @@ struct NetworkServiceDiscovery Just create an instance of AvailableServiceList and it will start listening - you can register a callback with its onChange member to find out when services appear/disappear, and you can call getServices() to find out the current list. + @see Service, Advertiser + + @tags{Events} */ struct AvailableServiceList : private Thread, private AsyncUpdater @@ -103,7 +113,7 @@ struct NetworkServiceDiscovery /** Destructor */ ~AvailableServiceList() override; - /** A lambda that can be set to recieve a callback when the list changes */ + /** A lambda that can be set to receive a callback when the list changes */ std::function onChange; /** Returns a list of the currently known services. */ diff --git a/modules/juce_events/juce_events.h b/modules/juce_events/juce_events.h index 078c50dc..316d90b6 100644 --- a/modules/juce_events/juce_events.h +++ b/modules/juce_events/juce_events.h @@ -20,6 +20,7 @@ ============================================================================== */ + /******************************************************************************* The block below describes the properties of this module, and is read by the Projucer to automatically generate project code that uses it. @@ -29,15 +30,15 @@ BEGIN_JUCE_MODULE_DECLARATION - ID: juce_events - vendor: juce - version: 5.4.5 - name: JUCE message and event handling classes - description: Classes for running an application's main event loop and sending/receiving messages, timers, etc. - website: http://www.juce.com/juce - license: ISC + ID: juce_events + vendor: juce + version: 5.4.6 + name: JUCE message and event handling classes + description: Classes for running an application's main event loop and sending/receiving messages, timers, etc. + website: http://www.juce.com/juce + license: ISC - dependencies: juce_core + dependencies: juce_core END_JUCE_MODULE_DECLARATION @@ -50,7 +51,7 @@ #include //============================================================================== -/** Config: JUCE_EXECUTE_APP_SUSPEND_ON_IOS_BACKGROUND_TASK +/** Config: JUCE_EXECUTE_APP_SUSPEND_ON_BACKGROUND_TASK Will execute your application's suspend method on an iOS background task, giving you extra time to save your applications state. */ diff --git a/modules/juce_events/messages/juce_MessageListener.cpp b/modules/juce_events/messages/juce_MessageListener.cpp index 78f18aa2..4a71d166 100644 --- a/modules/juce_events/messages/juce_MessageListener.cpp +++ b/modules/juce_events/messages/juce_MessageListener.cpp @@ -34,7 +34,7 @@ void Message::messageCallback() MessageListener::MessageListener() noexcept { - // Are you trying to create a messagelistener before or after juce has been intialised?? + // Are you trying to create a messagelistener before or after juce has been initialised?? JUCE_ASSERT_MESSAGE_MANAGER_EXISTS } diff --git a/modules/juce_events/messages/juce_MessageManager.h b/modules/juce_events/messages/juce_MessageManager.h index fd5e1013..22b2d189 100644 --- a/modules/juce_events/messages/juce_MessageManager.h +++ b/modules/juce_events/messages/juce_MessageManager.h @@ -223,14 +223,14 @@ public: If another thread is currently using the MessageManager, this will wait until that thread releases the lock to the MessageManager. - This call will only exit if the lock was accquired by this thread. Calling abort while + This call will only exit if the lock was acquired by this thread. Calling abort while a thread is waiting for enter to finish, will have no effect. @see exit, abort */ void enter() const noexcept; - /** Attempts to lock the meesage manager and exits if abort is called. + /** Attempts to lock the message manager and exits if abort is called. This method behaves identically to enter, except that it will abort waiting for the lock if the abort method is called. @@ -270,7 +270,7 @@ public: messageManagerLock.abort(); } - @returns false if waiting for a lock was aborted, true if the lock was accquired. + @returns false if waiting for a lock was aborted, true if the lock was acquired. @see enter, abort, ScopedTryLock */ bool tryEnter() const noexcept; @@ -283,7 +283,7 @@ public: /** Unblocks a thread which is waiting in tryEnter Call this method if you want to unblock a thread which is waiting for the MessageManager lock in tryEnter. - This method does not have any effetc on a thread waiting for a lock in enter. + This method does not have any effect on a thread waiting for a lock in enter. @see tryEnter */ void abort() const noexcept; diff --git a/modules/juce_events/native/juce_linux_Messaging.cpp b/modules/juce_events/native/juce_linux_Messaging.cpp index 7287d6c4..49b32b99 100644 --- a/modules/juce_events/native/juce_linux_Messaging.cpp +++ b/modules/juce_events/native/juce_linux_Messaging.cpp @@ -253,7 +253,7 @@ bool MessageManager::dispatchNextMessageOnSystemQueue (bool returnIfNoPendingMes for (;;) { if (LinuxErrorHandling::keyboardBreakOccurred) - JUCEApplicationBase::getInstance()->quit(); + JUCEApplicationBase::quit(); if (auto* runLoop = InternalRunLoop::getInstanceWithoutCreating()) { diff --git a/modules/juce_events/native/juce_win32_Messaging.cpp b/modules/juce_events/native/juce_win32_Messaging.cpp index d9eabdf5..e0f8945a 100644 --- a/modules/juce_events/native/juce_win32_Messaging.cpp +++ b/modules/juce_events/native/juce_win32_Messaging.cpp @@ -25,81 +25,141 @@ namespace juce extern HWND juce_messageWindowHandle; +#if JUCE_MODULE_AVAILABLE_juce_audio_plugin_client && JucePlugin_Build_Unity + bool juce_isRunningInUnity(); +#endif + +#if JUCE_MODULE_AVAILABLE_juce_gui_extra + LRESULT juce_offerEventToActiveXControl (::MSG&); +#endif + using CheckEventBlockedByModalComps = bool (*)(const MSG&); CheckEventBlockedByModalComps isEventBlockedByModalComps = nullptr; using SettingChangeCallbackFunc = void (*)(void); SettingChangeCallbackFunc settingChangeCallback = nullptr; -#if JUCE_MODULE_AVAILABLE_juce_audio_plugin_client && JucePlugin_Build_Unity - bool juce_isRunningInUnity(); -#endif - //============================================================================== -namespace WindowsMessageHelpers +class InternalMessageQueue { - const unsigned int customMessageID = WM_USER + 123; - const unsigned int broadcastMessageMagicNumber = 0xc403; +public: + InternalMessageQueue() + { + messageWindow = std::make_unique (messageWindowName, (WNDPROC) messageWndProc); + juce_messageWindowHandle = messageWindow->getHWND(); + } - const TCHAR messageWindowName[] = _T("JUCEWindow"); - std::unique_ptr messageWindow; + ~InternalMessageQueue() + { + juce_messageWindowHandle = 0; + clearSingletonInstance(); + } + + JUCE_DECLARE_SINGLETON (InternalMessageQueue, false) - void dispatchMessageFromLParam (LPARAM lParam) + //============================================================================== + void broadcastMessage (const String& message) { - if (auto message = reinterpret_cast (lParam)) - { - JUCE_TRY - { - message->messageCallback(); - } - JUCE_CATCH_EXCEPTION + auto localCopy = message; - message->decReferenceCount(); + Array windows; + EnumWindows (&broadcastEnumWindowProc, (LPARAM) &windows); + + for (int i = windows.size(); --i >= 0;) + { + COPYDATASTRUCT data; + data.dwData = broadcastMessageMagicNumber; + data.cbData = (localCopy.length() + 1) * sizeof (CharPointer_UTF32::CharType); + data.lpData = (void*) localCopy.toUTF32().getAddress(); + + DWORD_PTR result; + SendMessageTimeout (windows.getUnchecked (i), WM_COPYDATA, + (WPARAM) juce_messageWindowHandle, + (LPARAM) &data, + SMTO_BLOCK | SMTO_ABORTIFHUNG, 8000, &result); } } - BOOL CALLBACK broadcastEnumWindowProc (HWND hwnd, LPARAM lParam) + void postMessage (MessageManager::MessageBase* message) { - if (hwnd != juce_messageWindowHandle) + bool shouldTriggerMessageQueueDispatch = false; + { - TCHAR windowName[64] = { 0 }; // no need to read longer strings than this - GetWindowText (hwnd, windowName, 63); + const ScopedLock sl (lock); - if (String (windowName) == messageWindowName) - reinterpret_cast*> (lParam)->add (hwnd); + shouldTriggerMessageQueueDispatch = messageQueue.isEmpty(); + messageQueue.add (message); } - return TRUE; + if (! shouldTriggerMessageQueueDispatch) + return; + + #if JUCE_MODULE_AVAILABLE_juce_audio_plugin_client && JucePlugin_Build_Unity + if (juce_isRunningInUnity()) + { + SendNotifyMessage (juce_messageWindowHandle, customMessageID, 0, 0); + return; + } + #endif + + PostMessage (juce_messageWindowHandle, customMessageID, 0, 0); } - void handleBroadcastMessage (const COPYDATASTRUCT* data) + bool dispatchNextMessage (bool returnIfNoPendingMessages) { - if (data != nullptr && data->dwData == broadcastMessageMagicNumber) - { - struct BroadcastMessage : public CallbackMessage - { - BroadcastMessage (CharPointer_UTF32 text, size_t length) : message (text, length) {} - void messageCallback() override { MessageManager::getInstance()->deliverBroadcastMessage (message); } + MSG m; - String message; - }; + if (returnIfNoPendingMessages && ! PeekMessage (&m, (HWND) 0, 0, 0, PM_NOREMOVE)) + return false; - (new BroadcastMessage (CharPointer_UTF32 ((const CharPointer_UTF32::CharType*) data->lpData), - data->cbData / sizeof (CharPointer_UTF32::CharType))) - ->post(); + if (GetMessage (&m, (HWND) 0, 0, 0) >= 0) + { + #if JUCE_MODULE_AVAILABLE_juce_gui_extra + if (juce_offerEventToActiveXControl (m) != S_FALSE) + return true; + #endif + + if (m.message == customMessageID && m.hwnd == juce_messageWindowHandle) + { + dispatchMessages(); + } + else if (m.message == WM_QUIT) + { + if (auto* app = JUCEApplicationBase::getInstance()) + app->systemRequestedQuit(); + } + else if (isEventBlockedByModalComps == nullptr || ! isEventBlockedByModalComps (m)) + { + if ((m.message == WM_LBUTTONDOWN || m.message == WM_RBUTTONDOWN) + && ! JuceWindowIdentifier::isJUCEWindow (m.hwnd)) + { + // if it's someone else's window being clicked on, and the focus is + // currently on a juce window, pass the kb focus over.. + auto currentFocus = GetFocus(); + + if (currentFocus == 0 || JuceWindowIdentifier::isJUCEWindow (currentFocus)) + SetFocus (m.hwnd); + } + + TranslateMessage (&m); + DispatchMessage (&m); + } } + + return true; } +private: //============================================================================== - LRESULT CALLBACK messageWndProc (HWND h, UINT message, WPARAM wParam, LPARAM lParam) noexcept + static LRESULT CALLBACK messageWndProc (HWND h, UINT message, WPARAM wParam, LPARAM lParam) noexcept { if (h == juce_messageWindowHandle) { if (message == customMessageID) { - // (These are trapped early in our dispatch loop, but must also be checked - // here in case some 3rd-party code is running the dispatch loop). - dispatchMessageFromLParam (lParam); + if (auto* queue = InternalMessageQueue::getInstanceWithoutCreating()) + queue->dispatchMessages(); + return 0; } @@ -116,106 +176,125 @@ namespace WindowsMessageHelpers return DefWindowProc (h, message, wParam, lParam); } -} -#if JUCE_MODULE_AVAILABLE_juce_gui_extra -LRESULT juce_offerEventToActiveXControl (::MSG&); -#endif + static BOOL CALLBACK broadcastEnumWindowProc (HWND hwnd, LPARAM lParam) + { + if (hwnd != juce_messageWindowHandle) + { + TCHAR windowName[64] = { 0 }; // no need to read longer strings than this + GetWindowText (hwnd, windowName, 63); -//============================================================================== -bool MessageManager::dispatchNextMessageOnSystemQueue (bool returnIfNoPendingMessages) -{ - using namespace WindowsMessageHelpers; - MSG m; + if (String (windowName) == messageWindowName) + reinterpret_cast*> (lParam)->add (hwnd); + } - if (returnIfNoPendingMessages && ! PeekMessage (&m, (HWND) 0, 0, 0, PM_NOREMOVE)) - return false; + return TRUE; + } - if (GetMessage (&m, (HWND) 0, 0, 0) >= 0) + static void dispatchMessage (MessageManager::MessageBase* message) { - #if JUCE_MODULE_AVAILABLE_juce_gui_extra - if (juce_offerEventToActiveXControl (m) != S_FALSE) - return true; - #endif - - if (m.message == customMessageID && m.hwnd == juce_messageWindowHandle) + JUCE_TRY { - dispatchMessageFromLParam (m.lParam); + message->messageCallback(); } - else if (m.message == WM_QUIT) + JUCE_CATCH_EXCEPTION + + message->decReferenceCount(); + } + + static void handleBroadcastMessage (const COPYDATASTRUCT* data) + { + if (data != nullptr && data->dwData == broadcastMessageMagicNumber) { - if (auto* app = JUCEApplicationBase::getInstance()) - app->systemRequestedQuit(); + struct BroadcastMessage : public CallbackMessage + { + BroadcastMessage (CharPointer_UTF32 text, size_t length) : message (text, length) {} + void messageCallback() override { MessageManager::getInstance()->deliverBroadcastMessage (message); } + + String message; + }; + + (new BroadcastMessage (CharPointer_UTF32 ((const CharPointer_UTF32::CharType*) data->lpData), + data->cbData / sizeof (CharPointer_UTF32::CharType))) + ->post(); } - else if (isEventBlockedByModalComps == nullptr || ! isEventBlockedByModalComps (m)) + } + + void dispatchMessages() + { + ReferenceCountedArray messagesToDispatch; + { - if ((m.message == WM_LBUTTONDOWN || m.message == WM_RBUTTONDOWN) - && ! JuceWindowIdentifier::isJUCEWindow (m.hwnd)) - { - // if it's someone else's window being clicked on, and the focus is - // currently on a juce window, pass the kb focus over.. - auto currentFocus = GetFocus(); + const ScopedLock sl (lock); - if (currentFocus == 0 || JuceWindowIdentifier::isJUCEWindow (currentFocus)) - SetFocus (m.hwnd); - } + if (messageQueue.isEmpty()) + return; - TranslateMessage (&m); - DispatchMessage (&m); + messagesToDispatch.swapWith (messageQueue); + } + + for (int i = 0; i < messagesToDispatch.size(); ++i) + { + auto message = messagesToDispatch.getUnchecked (i); + message->incReferenceCount(); + dispatchMessage (message.get()); } } - return true; -} + //============================================================================== + static constexpr unsigned int customMessageID = WM_USER + 123; + static constexpr unsigned int broadcastMessageMagicNumber = 0xc403; + static const TCHAR messageWindowName[]; -bool MessageManager::postMessageToSystemQueue (MessageManager::MessageBase* const message) -{ - message->incReferenceCount(); + std::unique_ptr messageWindow; - #if JUCE_MODULE_AVAILABLE_juce_audio_plugin_client && JucePlugin_Build_Unity - if (juce_isRunningInUnity()) - return SendNotifyMessage (juce_messageWindowHandle, WindowsMessageHelpers::customMessageID, 0, (LPARAM) message) != 0; - #endif + CriticalSection lock; + ReferenceCountedArray messageQueue; - return PostMessage (juce_messageWindowHandle, WindowsMessageHelpers::customMessageID, 0, (LPARAM) message) != 0; -} + //============================================================================== + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (InternalMessageQueue) +}; -void MessageManager::broadcastMessage (const String& value) +JUCE_IMPLEMENT_SINGLETON (InternalMessageQueue) + +const TCHAR InternalMessageQueue::messageWindowName[] = _T("JUCEWindow"); + +//============================================================================== +bool MessageManager::dispatchNextMessageOnSystemQueue (bool returnIfNoPendingMessages) { - auto localCopy = value; + if (auto* queue = InternalMessageQueue::getInstanceWithoutCreating()) + return queue->dispatchNextMessage (returnIfNoPendingMessages); - Array windows; - EnumWindows (&WindowsMessageHelpers::broadcastEnumWindowProc, (LPARAM) &windows); + return false; +} - for (int i = windows.size(); --i >= 0;) +bool MessageManager::postMessageToSystemQueue (MessageManager::MessageBase* const message) +{ + if (auto* queue = InternalMessageQueue::getInstanceWithoutCreating()) { - COPYDATASTRUCT data; - data.dwData = WindowsMessageHelpers::broadcastMessageMagicNumber; - data.cbData = (localCopy.length() + 1) * sizeof (CharPointer_UTF32::CharType); - data.lpData = (void*) localCopy.toUTF32().getAddress(); - - DWORD_PTR result; - SendMessageTimeout (windows.getUnchecked (i), WM_COPYDATA, - (WPARAM) juce_messageWindowHandle, - (LPARAM) &data, - SMTO_BLOCK | SMTO_ABORTIFHUNG, 8000, &result); + queue->postMessage (message); + return true; } + + return false; +} + +void MessageManager::broadcastMessage (const String& value) +{ + if (auto* queue = InternalMessageQueue::getInstanceWithoutCreating()) + queue->broadcastMessage (value); } //============================================================================== void MessageManager::doPlatformSpecificInitialisation() { OleInitialize (0); - - using namespace WindowsMessageHelpers; - messageWindow.reset (new HiddenMessageWindow (messageWindowName, (WNDPROC) messageWndProc)); - juce_messageWindowHandle = messageWindow->getHWND(); + InternalMessageQueue::getInstance(); } void MessageManager::doPlatformSpecificShutdown() { - WindowsMessageHelpers::messageWindow = nullptr; - + InternalMessageQueue::deleteInstance(); OleUninitialize(); } diff --git a/modules/juce_graphics/colour/juce_Colour.h b/modules/juce_graphics/colour/juce_Colour.h index 31ab62b6..8117e9ae 100644 --- a/modules/juce_graphics/colour/juce_Colour.h +++ b/modules/juce_graphics/colour/juce_Colour.h @@ -284,7 +284,7 @@ public: */ Colour withBrightness (float newBrightness) const noexcept; - /** Returns a copy of this colour with it hue rotated. + /** Returns a copy of this colour with its hue rotated. The new colour's hue is ((this->getHue() + amountToRotate) % 1.0) @see brighter, darker, withMultipliedBrightness */ diff --git a/modules/juce_graphics/colour/juce_Colours.cpp b/modules/juce_graphics/colour/juce_Colours.cpp index 2b062912..926157bc 100644 --- a/modules/juce_graphics/colour/juce_Colours.cpp +++ b/modules/juce_graphics/colour/juce_Colours.cpp @@ -27,307 +27,162 @@ namespace juce { -const Colour Colours::transparentBlack (0); -const Colour Colours::transparentWhite (0x00ffffff); - -const Colour Colours::aliceblue (0xfff0f8ff); -const Colour Colours::antiquewhite (0xfffaebd7); -const Colour Colours::aqua (0xff00ffff); -const Colour Colours::aquamarine (0xff7fffd4); -const Colour Colours::azure (0xfff0ffff); -const Colour Colours::beige (0xfff5f5dc); -const Colour Colours::bisque (0xffffe4c4); -const Colour Colours::black (0xff000000); -const Colour Colours::blanchedalmond (0xffffebcd); -const Colour Colours::blue (0xff0000ff); -const Colour Colours::blueviolet (0xff8a2be2); -const Colour Colours::brown (0xffa52a2a); -const Colour Colours::burlywood (0xffdeb887); -const Colour Colours::cadetblue (0xff5f9ea0); -const Colour Colours::chartreuse (0xff7fff00); -const Colour Colours::chocolate (0xffd2691e); -const Colour Colours::coral (0xffff7f50); -const Colour Colours::cornflowerblue (0xff6495ed); -const Colour Colours::cornsilk (0xfffff8dc); -const Colour Colours::crimson (0xffdc143c); -const Colour Colours::cyan (0xff00ffff); -const Colour Colours::darkblue (0xff00008b); -const Colour Colours::darkcyan (0xff008b8b); -const Colour Colours::darkgoldenrod (0xffb8860b); -const Colour Colours::darkgrey (0xff555555); -const Colour Colours::darkgreen (0xff006400); -const Colour Colours::darkkhaki (0xffbdb76b); -const Colour Colours::darkmagenta (0xff8b008b); -const Colour Colours::darkolivegreen (0xff556b2f); -const Colour Colours::darkorange (0xffff8c00); -const Colour Colours::darkorchid (0xff9932cc); -const Colour Colours::darkred (0xff8b0000); -const Colour Colours::darksalmon (0xffe9967a); -const Colour Colours::darkseagreen (0xff8fbc8f); -const Colour Colours::darkslateblue (0xff483d8b); -const Colour Colours::darkslategrey (0xff2f4f4f); -const Colour Colours::darkturquoise (0xff00ced1); -const Colour Colours::darkviolet (0xff9400d3); -const Colour Colours::deeppink (0xffff1493); -const Colour Colours::deepskyblue (0xff00bfff); -const Colour Colours::dimgrey (0xff696969); -const Colour Colours::dodgerblue (0xff1e90ff); -const Colour Colours::firebrick (0xffb22222); -const Colour Colours::floralwhite (0xfffffaf0); -const Colour Colours::forestgreen (0xff228b22); -const Colour Colours::fuchsia (0xffff00ff); -const Colour Colours::gainsboro (0xffdcdcdc); -const Colour Colours::ghostwhite (0xfff8f8ff); -const Colour Colours::gold (0xffffd700); -const Colour Colours::goldenrod (0xffdaa520); -const Colour Colours::grey (0xff808080); -const Colour Colours::green (0xff008000); -const Colour Colours::greenyellow (0xffadff2f); -const Colour Colours::honeydew (0xfff0fff0); -const Colour Colours::hotpink (0xffff69b4); -const Colour Colours::indianred (0xffcd5c5c); -const Colour Colours::indigo (0xff4b0082); -const Colour Colours::ivory (0xfffffff0); -const Colour Colours::khaki (0xfff0e68c); -const Colour Colours::lavender (0xffe6e6fa); -const Colour Colours::lavenderblush (0xfffff0f5); -const Colour Colours::lawngreen (0xff7cfc00); -const Colour Colours::lemonchiffon (0xfffffacd); -const Colour Colours::lightblue (0xffadd8e6); -const Colour Colours::lightcoral (0xfff08080); -const Colour Colours::lightcyan (0xffe0ffff); -const Colour Colours::lightgoldenrodyellow (0xfffafad2); -const Colour Colours::lightgreen (0xff90ee90); -const Colour Colours::lightgrey (0xffd3d3d3); -const Colour Colours::lightpink (0xffffb6c1); -const Colour Colours::lightsalmon (0xffffa07a); -const Colour Colours::lightseagreen (0xff20b2aa); -const Colour Colours::lightskyblue (0xff87cefa); -const Colour Colours::lightslategrey (0xff778899); -const Colour Colours::lightsteelblue (0xffb0c4de); -const Colour Colours::lightyellow (0xffffffe0); -const Colour Colours::lime (0xff00ff00); -const Colour Colours::limegreen (0xff32cd32); -const Colour Colours::linen (0xfffaf0e6); -const Colour Colours::magenta (0xffff00ff); -const Colour Colours::maroon (0xff800000); -const Colour Colours::mediumaquamarine (0xff66cdaa); -const Colour Colours::mediumblue (0xff0000cd); -const Colour Colours::mediumorchid (0xffba55d3); -const Colour Colours::mediumpurple (0xff9370db); -const Colour Colours::mediumseagreen (0xff3cb371); -const Colour Colours::mediumslateblue (0xff7b68ee); -const Colour Colours::mediumspringgreen (0xff00fa9a); -const Colour Colours::mediumturquoise (0xff48d1cc); -const Colour Colours::mediumvioletred (0xffc71585); -const Colour Colours::midnightblue (0xff191970); -const Colour Colours::mintcream (0xfff5fffa); -const Colour Colours::mistyrose (0xffffe4e1); -const Colour Colours::moccasin (0xffffe4b5); -const Colour Colours::navajowhite (0xffffdead); -const Colour Colours::navy (0xff000080); -const Colour Colours::oldlace (0xfffdf5e6); -const Colour Colours::olive (0xff808000); -const Colour Colours::olivedrab (0xff6b8e23); -const Colour Colours::orange (0xffffa500); -const Colour Colours::orangered (0xffff4500); -const Colour Colours::orchid (0xffda70d6); -const Colour Colours::palegoldenrod (0xffeee8aa); -const Colour Colours::palegreen (0xff98fb98); -const Colour Colours::paleturquoise (0xffafeeee); -const Colour Colours::palevioletred (0xffdb7093); -const Colour Colours::papayawhip (0xffffefd5); -const Colour Colours::peachpuff (0xffffdab9); -const Colour Colours::peru (0xffcd853f); -const Colour Colours::pink (0xffffc0cb); -const Colour Colours::plum (0xffdda0dd); -const Colour Colours::powderblue (0xffb0e0e6); -const Colour Colours::purple (0xff800080); -const Colour Colours::rebeccapurple (0xff663399); -const Colour Colours::red (0xffff0000); -const Colour Colours::rosybrown (0xffbc8f8f); -const Colour Colours::royalblue (0xff4169e1); -const Colour Colours::saddlebrown (0xff8b4513); -const Colour Colours::salmon (0xfffa8072); -const Colour Colours::sandybrown (0xfff4a460); -const Colour Colours::seagreen (0xff2e8b57); -const Colour Colours::seashell (0xfffff5ee); -const Colour Colours::sienna (0xffa0522d); -const Colour Colours::silver (0xffc0c0c0); -const Colour Colours::skyblue (0xff87ceeb); -const Colour Colours::slateblue (0xff6a5acd); -const Colour Colours::slategrey (0xff708090); -const Colour Colours::snow (0xfffffafa); -const Colour Colours::springgreen (0xff00ff7f); -const Colour Colours::steelblue (0xff4682b4); -const Colour Colours::tan (0xffd2b48c); -const Colour Colours::teal (0xff008080); -const Colour Colours::thistle (0xffd8bfd8); -const Colour Colours::tomato (0xffff6347); -const Colour Colours::turquoise (0xff40e0d0); -const Colour Colours::violet (0xffee82ee); -const Colour Colours::wheat (0xfff5deb3); -const Colour Colours::white (0xffffffff); -const Colour Colours::whitesmoke (0xfff5f5f5); -const Colour Colours::yellow (0xffffff00); -const Colour Colours::yellowgreen (0xff9acd32); - //============================================================================== Colour Colours::findColourForName (const String& colourName, Colour defaultColour) { - static const uint32 presets[] = - { - // (first value is the string's hashcode, second is ARGB) + struct StringHashAndColour { uint32 stringHash, colour; }; - 0x05978fff, 0xff000000, /* black */ - 0x06bdcc29, 0xffffffff, /* white */ - 0x002e305a, 0xff0000ff, /* blue */ - 0x00308adf, 0xff808080, /* grey */ - 0x05e0cf03, 0xff008000, /* green */ - 0x0001b891, 0xffff0000, /* red */ - 0xd43c6474, 0xffffff00, /* yellow */ - 0x620886da, 0xfff0f8ff, /* aliceblue */ - 0x20a2676a, 0xfffaebd7, /* antiquewhite */ - 0x002dcebc, 0xff00ffff, /* aqua */ - 0x46bb5f7e, 0xff7fffd4, /* aquamarine */ - 0x0590228f, 0xfff0ffff, /* azure */ - 0x05947fe4, 0xfff5f5dc, /* beige */ - 0xad388e35, 0xffffe4c4, /* bisque */ - 0x00674f7e, 0xffffebcd, /* blanchedalmond */ - 0x39129959, 0xff8a2be2, /* blueviolet */ - 0x059a8136, 0xffa52a2a, /* brown */ - 0x89cea8f9, 0xffdeb887, /* burlywood */ - 0x0fa260cf, 0xff5f9ea0, /* cadetblue */ - 0x6b748956, 0xff7fff00, /* chartreuse */ - 0x2903623c, 0xffd2691e, /* chocolate */ - 0x05a74431, 0xffff7f50, /* coral */ - 0x618d42dd, 0xff6495ed, /* cornflowerblue */ - 0xe4b479fd, 0xfffff8dc, /* cornsilk */ - 0x3d8c4edf, 0xffdc143c, /* crimson */ - 0x002ed323, 0xff00ffff, /* cyan */ - 0x67cc74d0, 0xff00008b, /* darkblue */ - 0x67cd1799, 0xff008b8b, /* darkcyan */ - 0x31bbd168, 0xffb8860b, /* darkgoldenrod */ - 0x67cecf55, 0xff555555, /* darkgrey */ - 0x920b194d, 0xff006400, /* darkgreen */ - 0x923edd4c, 0xffbdb76b, /* darkkhaki */ - 0x5c293873, 0xff8b008b, /* darkmagenta */ - 0x6b6671fe, 0xff556b2f, /* darkolivegreen */ - 0xbcfd2524, 0xffff8c00, /* darkorange */ - 0xbcfdf799, 0xff9932cc, /* darkorchid */ - 0x55ee0d5b, 0xff8b0000, /* darkred */ - 0xc2e5f564, 0xffe9967a, /* darksalmon */ - 0x61be858a, 0xff8fbc8f, /* darkseagreen */ - 0xc2b0f2bd, 0xff483d8b, /* darkslateblue */ - 0xc2b34d42, 0xff2f4f4f, /* darkslategrey */ - 0x7cf2b06b, 0xff00ced1, /* darkturquoise */ - 0xc8769375, 0xff9400d3, /* darkviolet */ - 0x25832862, 0xffff1493, /* deeppink */ - 0xfcad568f, 0xff00bfff, /* deepskyblue */ - 0x634c8b67, 0xff696969, /* dimgrey */ - 0x45c1ce55, 0xff1e90ff, /* dodgerblue */ - 0xef19e3cb, 0xffb22222, /* firebrick */ - 0xb852b195, 0xfffffaf0, /* floralwhite */ - 0xd086fd06, 0xff228b22, /* forestgreen */ - 0xe106b6d7, 0xffff00ff, /* fuchsia */ - 0x7880d61e, 0xffdcdcdc, /* gainsboro */ - 0x2018a2fa, 0xfff8f8ff, /* ghostwhite */ - 0x00308060, 0xffffd700, /* gold */ - 0xb3b3bc1e, 0xffdaa520, /* goldenrod */ - 0xbab8a537, 0xffadff2f, /* greenyellow */ - 0xe4cacafb, 0xfff0fff0, /* honeydew */ - 0x41892743, 0xffff69b4, /* hotpink */ - 0xd5796f1a, 0xffcd5c5c, /* indianred */ - 0xb969fed2, 0xff4b0082, /* indigo */ - 0x05fef6a9, 0xfffffff0, /* ivory */ - 0x06149302, 0xfff0e68c, /* khaki */ - 0xad5a05c7, 0xffe6e6fa, /* lavender */ - 0x7c4d5b99, 0xfffff0f5, /* lavenderblush */ - 0x41cc4377, 0xff7cfc00, /* lawngreen */ - 0x195756f0, 0xfffffacd, /* lemonchiffon */ - 0x28e4ea70, 0xffadd8e6, /* lightblue */ - 0xf3c7ccdb, 0xfff08080, /* lightcoral */ - 0x28e58d39, 0xffe0ffff, /* lightcyan */ - 0x21234e3c, 0xfffafad2, /* lightgoldenrodyellow */ - 0xf40157ad, 0xff90ee90, /* lightgreen */ - 0x28e744f5, 0xffd3d3d3, /* lightgrey */ - 0x28eb3b8c, 0xffffb6c1, /* lightpink */ - 0x9fb78304, 0xffffa07a, /* lightsalmon */ - 0x50632b2a, 0xff20b2aa, /* lightseagreen */ - 0x68fb7b25, 0xff87cefa, /* lightskyblue */ - 0xa8a35ba2, 0xff778899, /* lightslategrey */ - 0xa20d484f, 0xffb0c4de, /* lightsteelblue */ - 0xaa2cf10a, 0xffffffe0, /* lightyellow */ - 0x0032afd5, 0xff00ff00, /* lime */ - 0x607bbc4e, 0xff32cd32, /* limegreen */ - 0x06234efa, 0xfffaf0e6, /* linen */ - 0x316858a9, 0xffff00ff, /* magenta */ - 0xbf8ca470, 0xff800000, /* maroon */ - 0xbd58e0b3, 0xff66cdaa, /* mediumaquamarine */ - 0x967dfd4f, 0xff0000cd, /* mediumblue */ - 0x056f5c58, 0xffba55d3, /* mediumorchid */ - 0x07556b71, 0xff9370db, /* mediumpurple */ - 0x5369b689, 0xff3cb371, /* mediumseagreen */ - 0x066be19e, 0xff7b68ee, /* mediumslateblue */ - 0x3256b281, 0xff00fa9a, /* mediumspringgreen */ - 0xc0ad9f4c, 0xff48d1cc, /* mediumturquoise */ - 0x628e63dd, 0xffc71585, /* mediumvioletred */ - 0x168eb32a, 0xff191970, /* midnightblue */ - 0x4306b960, 0xfff5fffa, /* mintcream */ - 0x4cbc0e6b, 0xffffe4e1, /* mistyrose */ - 0xd9447d59, 0xffffe4b5, /* moccasin */ - 0xe97218a6, 0xffffdead, /* navajowhite */ - 0x00337bb6, 0xff000080, /* navy */ - 0xadd2d33e, 0xfffdf5e6, /* oldlace */ - 0x064ee1db, 0xff808000, /* olive */ - 0x9e33a98a, 0xff6b8e23, /* olivedrab */ - 0xc3de262e, 0xffffa500, /* orange */ - 0x58bebba3, 0xffff4500, /* orangered */ - 0xc3def8a3, 0xffda70d6, /* orchid */ - 0x28cb4834, 0xffeee8aa, /* palegoldenrod */ - 0x3d9dd619, 0xff98fb98, /* palegreen */ - 0x74022737, 0xffafeeee, /* paleturquoise */ - 0x15e2ebc8, 0xffdb7093, /* palevioletred */ - 0x5fd898e2, 0xffffefd5, /* papayawhip */ - 0x93e1b776, 0xffffdab9, /* peachpuff */ - 0x003472f8, 0xffcd853f, /* peru */ - 0x00348176, 0xffffc0cb, /* pink */ - 0x00348d94, 0xffdda0dd, /* plum */ - 0xd036be93, 0xffb0e0e6, /* powderblue */ - 0xc5c507bc, 0xff800080, /* purple */ - 0xf381f607, 0xff663399, /* rebeccapurple */ - 0xa89d65b3, 0xffbc8f8f, /* rosybrown */ - 0xbd9413e1, 0xff4169e1, /* royalblue */ - 0xf456044f, 0xff8b4513, /* saddlebrown */ - 0xc9c6f66e, 0xfffa8072, /* salmon */ - 0x0bb131e1, 0xfff4a460, /* sandybrown */ - 0x34636c14, 0xff2e8b57, /* seagreen */ - 0x3507fb41, 0xfffff5ee, /* seashell */ - 0xca348772, 0xffa0522d, /* sienna */ - 0xca37d30d, 0xffc0c0c0, /* silver */ - 0x80da74fb, 0xff87ceeb, /* skyblue */ - 0x44a8dd73, 0xff6a5acd, /* slateblue */ - 0x44ab37f8, 0xff708090, /* slategrey */ - 0x0035f183, 0xfffffafa, /* snow */ - 0xd5440d16, 0xff00ff7f, /* springgreen */ - 0x3e1524a5, 0xff4682b4, /* steelblue */ - 0x0001bfa1, 0xffd2b48c, /* tan */ - 0x0036425c, 0xff008080, /* teal */ - 0xafc8858f, 0xffd8bfd8, /* thistle */ - 0xcc41600a, 0xffff6347, /* tomato */ - 0xfeea9b21, 0xff40e0d0, /* turquoise */ - 0xcf57947f, 0xffee82ee, /* violet */ - 0x06bdbae7, 0xfff5deb3, /* wheat */ - 0x10802ee6, 0xfff5f5f5, /* whitesmoke */ - 0xe1b5130f, 0xff9acd32 /* yellowgreen */ + static const StringHashAndColour presets[] + { + { 0x05978fff, 0xff000000 }, /* black */ + { 0x06bdcc29, 0xffffffff }, /* white */ + { 0x002e305a, 0xff0000ff }, /* blue */ + { 0x00308adf, 0xff808080 }, /* grey */ + { 0x05e0cf03, 0xff008000 }, /* green */ + { 0x0001b891, 0xffff0000 }, /* red */ + { 0xd43c6474, 0xffffff00 }, /* yellow */ + { 0x620886da, 0xfff0f8ff }, /* aliceblue */ + { 0x20a2676a, 0xfffaebd7 }, /* antiquewhite */ + { 0x002dcebc, 0xff00ffff }, /* aqua */ + { 0x46bb5f7e, 0xff7fffd4 }, /* aquamarine */ + { 0x0590228f, 0xfff0ffff }, /* azure */ + { 0x05947fe4, 0xfff5f5dc }, /* beige */ + { 0xad388e35, 0xffffe4c4 }, /* bisque */ + { 0x00674f7e, 0xffffebcd }, /* blanchedalmond */ + { 0x39129959, 0xff8a2be2 }, /* blueviolet */ + { 0x059a8136, 0xffa52a2a }, /* brown */ + { 0x89cea8f9, 0xffdeb887 }, /* burlywood */ + { 0x0fa260cf, 0xff5f9ea0 }, /* cadetblue */ + { 0x6b748956, 0xff7fff00 }, /* chartreuse */ + { 0x2903623c, 0xffd2691e }, /* chocolate */ + { 0x05a74431, 0xffff7f50 }, /* coral */ + { 0x618d42dd, 0xff6495ed }, /* cornflowerblue */ + { 0xe4b479fd, 0xfffff8dc }, /* cornsilk */ + { 0x3d8c4edf, 0xffdc143c }, /* crimson */ + { 0x002ed323, 0xff00ffff }, /* cyan */ + { 0x67cc74d0, 0xff00008b }, /* darkblue */ + { 0x67cd1799, 0xff008b8b }, /* darkcyan */ + { 0x31bbd168, 0xffb8860b }, /* darkgoldenrod */ + { 0x67cecf55, 0xff555555 }, /* darkgrey */ + { 0x920b194d, 0xff006400 }, /* darkgreen */ + { 0x923edd4c, 0xffbdb76b }, /* darkkhaki */ + { 0x5c293873, 0xff8b008b }, /* darkmagenta */ + { 0x6b6671fe, 0xff556b2f }, /* darkolivegreen */ + { 0xbcfd2524, 0xffff8c00 }, /* darkorange */ + { 0xbcfdf799, 0xff9932cc }, /* darkorchid */ + { 0x55ee0d5b, 0xff8b0000 }, /* darkred */ + { 0xc2e5f564, 0xffe9967a }, /* darksalmon */ + { 0x61be858a, 0xff8fbc8f }, /* darkseagreen */ + { 0xc2b0f2bd, 0xff483d8b }, /* darkslateblue */ + { 0xc2b34d42, 0xff2f4f4f }, /* darkslategrey */ + { 0x7cf2b06b, 0xff00ced1 }, /* darkturquoise */ + { 0xc8769375, 0xff9400d3 }, /* darkviolet */ + { 0x25832862, 0xffff1493 }, /* deeppink */ + { 0xfcad568f, 0xff00bfff }, /* deepskyblue */ + { 0x634c8b67, 0xff696969 }, /* dimgrey */ + { 0x45c1ce55, 0xff1e90ff }, /* dodgerblue */ + { 0xef19e3cb, 0xffb22222 }, /* firebrick */ + { 0xb852b195, 0xfffffaf0 }, /* floralwhite */ + { 0xd086fd06, 0xff228b22 }, /* forestgreen */ + { 0xe106b6d7, 0xffff00ff }, /* fuchsia */ + { 0x7880d61e, 0xffdcdcdc }, /* gainsboro */ + { 0x2018a2fa, 0xfff8f8ff }, /* ghostwhite */ + { 0x00308060, 0xffffd700 }, /* gold */ + { 0xb3b3bc1e, 0xffdaa520 }, /* goldenrod */ + { 0xbab8a537, 0xffadff2f }, /* greenyellow */ + { 0xe4cacafb, 0xfff0fff0 }, /* honeydew */ + { 0x41892743, 0xffff69b4 }, /* hotpink */ + { 0xd5796f1a, 0xffcd5c5c }, /* indianred */ + { 0xb969fed2, 0xff4b0082 }, /* indigo */ + { 0x05fef6a9, 0xfffffff0 }, /* ivory */ + { 0x06149302, 0xfff0e68c }, /* khaki */ + { 0xad5a05c7, 0xffe6e6fa }, /* lavender */ + { 0x7c4d5b99, 0xfffff0f5 }, /* lavenderblush */ + { 0x41cc4377, 0xff7cfc00 }, /* lawngreen */ + { 0x195756f0, 0xfffffacd }, /* lemonchiffon */ + { 0x28e4ea70, 0xffadd8e6 }, /* lightblue */ + { 0xf3c7ccdb, 0xfff08080 }, /* lightcoral */ + { 0x28e58d39, 0xffe0ffff }, /* lightcyan */ + { 0x21234e3c, 0xfffafad2 }, /* lightgoldenrodyellow */ + { 0xf40157ad, 0xff90ee90 }, /* lightgreen */ + { 0x28e744f5, 0xffd3d3d3 }, /* lightgrey */ + { 0x28eb3b8c, 0xffffb6c1 }, /* lightpink */ + { 0x9fb78304, 0xffffa07a }, /* lightsalmon */ + { 0x50632b2a, 0xff20b2aa }, /* lightseagreen */ + { 0x68fb7b25, 0xff87cefa }, /* lightskyblue */ + { 0xa8a35ba2, 0xff778899 }, /* lightslategrey */ + { 0xa20d484f, 0xffb0c4de }, /* lightsteelblue */ + { 0xaa2cf10a, 0xffffffe0 }, /* lightyellow */ + { 0x0032afd5, 0xff00ff00 }, /* lime */ + { 0x607bbc4e, 0xff32cd32 }, /* limegreen */ + { 0x06234efa, 0xfffaf0e6 }, /* linen */ + { 0x316858a9, 0xffff00ff }, /* magenta */ + { 0xbf8ca470, 0xff800000 }, /* maroon */ + { 0xbd58e0b3, 0xff66cdaa }, /* mediumaquamarine */ + { 0x967dfd4f, 0xff0000cd }, /* mediumblue */ + { 0x056f5c58, 0xffba55d3 }, /* mediumorchid */ + { 0x07556b71, 0xff9370db }, /* mediumpurple */ + { 0x5369b689, 0xff3cb371 }, /* mediumseagreen */ + { 0x066be19e, 0xff7b68ee }, /* mediumslateblue */ + { 0x3256b281, 0xff00fa9a }, /* mediumspringgreen */ + { 0xc0ad9f4c, 0xff48d1cc }, /* mediumturquoise */ + { 0x628e63dd, 0xffc71585 }, /* mediumvioletred */ + { 0x168eb32a, 0xff191970 }, /* midnightblue */ + { 0x4306b960, 0xfff5fffa }, /* mintcream */ + { 0x4cbc0e6b, 0xffffe4e1 }, /* mistyrose */ + { 0xd9447d59, 0xffffe4b5 }, /* moccasin */ + { 0xe97218a6, 0xffffdead }, /* navajowhite */ + { 0x00337bb6, 0xff000080 }, /* navy */ + { 0xadd2d33e, 0xfffdf5e6 }, /* oldlace */ + { 0x064ee1db, 0xff808000 }, /* olive */ + { 0x9e33a98a, 0xff6b8e23 }, /* olivedrab */ + { 0xc3de262e, 0xffffa500 }, /* orange */ + { 0x58bebba3, 0xffff4500 }, /* orangered */ + { 0xc3def8a3, 0xffda70d6 }, /* orchid */ + { 0x28cb4834, 0xffeee8aa }, /* palegoldenrod */ + { 0x3d9dd619, 0xff98fb98 }, /* palegreen */ + { 0x74022737, 0xffafeeee }, /* paleturquoise */ + { 0x15e2ebc8, 0xffdb7093 }, /* palevioletred */ + { 0x5fd898e2, 0xffffefd5 }, /* papayawhip */ + { 0x93e1b776, 0xffffdab9 }, /* peachpuff */ + { 0x003472f8, 0xffcd853f }, /* peru */ + { 0x00348176, 0xffffc0cb }, /* pink */ + { 0x00348d94, 0xffdda0dd }, /* plum */ + { 0xd036be93, 0xffb0e0e6 }, /* powderblue */ + { 0xc5c507bc, 0xff800080 }, /* purple */ + { 0xf381f607, 0xff663399 }, /* rebeccapurple */ + { 0xa89d65b3, 0xffbc8f8f }, /* rosybrown */ + { 0xbd9413e1, 0xff4169e1 }, /* royalblue */ + { 0xf456044f, 0xff8b4513 }, /* saddlebrown */ + { 0xc9c6f66e, 0xfffa8072 }, /* salmon */ + { 0x0bb131e1, 0xfff4a460 }, /* sandybrown */ + { 0x34636c14, 0xff2e8b57 }, /* seagreen */ + { 0x3507fb41, 0xfffff5ee }, /* seashell */ + { 0xca348772, 0xffa0522d }, /* sienna */ + { 0xca37d30d, 0xffc0c0c0 }, /* silver */ + { 0x80da74fb, 0xff87ceeb }, /* skyblue */ + { 0x44a8dd73, 0xff6a5acd }, /* slateblue */ + { 0x44ab37f8, 0xff708090 }, /* slategrey */ + { 0x0035f183, 0xfffffafa }, /* snow */ + { 0xd5440d16, 0xff00ff7f }, /* springgreen */ + { 0x3e1524a5, 0xff4682b4 }, /* steelblue */ + { 0x0001bfa1, 0xffd2b48c }, /* tan */ + { 0x0036425c, 0xff008080 }, /* teal */ + { 0xafc8858f, 0xffd8bfd8 }, /* thistle */ + { 0xcc41600a, 0xffff6347 }, /* tomato */ + { 0xfeea9b21, 0xff40e0d0 }, /* turquoise */ + { 0xcf57947f, 0xffee82ee }, /* violet */ + { 0x06bdbae7, 0xfff5deb3 }, /* wheat */ + { 0x10802ee6, 0xfff5f5f5 }, /* whitesmoke */ + { 0xe1b5130f, 0xff9acd32 }, /* yellowgreen */ }; - const uint32 hash = (uint32) colourName.trim().toLowerCase().hashCode(); + const auto hash = (uint32) colourName.trim().toLowerCase().hashCode(); - for (int i = 0; i < numElementsInArray (presets); i += 2) - if (presets [i] == hash) - return Colour (presets [i + 1]); + for (auto entry : presets) + if (entry.stringHash == hash) + return Colour (entry.colour); return defaultColour; } diff --git a/modules/juce_graphics/colour/juce_Colours.h b/modules/juce_graphics/colour/juce_Colours.h index 2acb8d9f..370f6b44 100644 --- a/modules/juce_graphics/colour/juce_Colours.h +++ b/modules/juce_graphics/colour/juce_Colours.h @@ -35,59 +35,153 @@ namespace juce @tags{Graphics} */ -class Colours +namespace Colours { -public: - static JUCE_API const Colour - - //============================================================================== - transparentBlack, /**< ARGB = 0x00000000 */ - transparentWhite, /**< ARGB = 0x00ffffff */ - - //============================================================================== - black, /**< ARGB = 0xff000000 */ - white, /**< ARGB = 0xffffffff */ - blue, /**< ARGB = 0xff0000ff */ - grey, /**< ARGB = 0xff808080 */ - green, /**< ARGB = 0xff008000 */ - red, /**< ARGB = 0xffff0000 */ - yellow, /**< ARGB = 0xffffff00 */ - - //============================================================================== - aliceblue, antiquewhite, aqua, aquamarine, - azure, beige, bisque, blanchedalmond, - blueviolet, brown, burlywood, cadetblue, - chartreuse, chocolate, coral, cornflowerblue, - cornsilk, crimson, cyan, darkblue, - darkcyan, darkgoldenrod, darkgrey, darkgreen, - darkkhaki, darkmagenta, darkolivegreen, darkorange, - darkorchid, darkred, darksalmon, darkseagreen, - darkslateblue, darkslategrey, darkturquoise, darkviolet, - deeppink, deepskyblue, dimgrey, dodgerblue, - firebrick, floralwhite, forestgreen, fuchsia, - gainsboro, ghostwhite, gold, goldenrod, - greenyellow, honeydew, hotpink, indianred, - indigo, ivory, khaki, lavender, - lavenderblush, lawngreen, lemonchiffon, lightblue, - lightcoral, lightcyan, lightgoldenrodyellow, lightgreen, - lightgrey, lightpink, lightsalmon, lightseagreen, - lightskyblue, lightslategrey, lightsteelblue, lightyellow, - lime, limegreen, linen, magenta, - maroon, mediumaquamarine, mediumblue, mediumorchid, - mediumpurple, mediumseagreen, mediumslateblue, mediumspringgreen, - mediumturquoise, mediumvioletred, midnightblue, mintcream, - mistyrose, moccasin, navajowhite, navy, - oldlace, olive, olivedrab, orange, - orangered, orchid, palegoldenrod, palegreen, - paleturquoise, palevioletred, papayawhip, peachpuff, - peru, pink, plum, powderblue, - purple, rebeccapurple, rosybrown, royalblue, - saddlebrown, salmon, sandybrown, seagreen, - seashell, sienna, silver, skyblue, - slateblue, slategrey, snow, springgreen, - steelblue, tan, teal, thistle, - tomato, turquoise, violet, wheat, - whitesmoke, yellowgreen; + + const Colour transparentBlack { 0 }; + const Colour transparentWhite { 0x00ffffff }; + + const Colour aliceblue { 0xfff0f8ff }; + const Colour antiquewhite { 0xfffaebd7 }; + const Colour aqua { 0xff00ffff }; + const Colour aquamarine { 0xff7fffd4 }; + const Colour azure { 0xfff0ffff }; + const Colour beige { 0xfff5f5dc }; + const Colour bisque { 0xffffe4c4 }; + const Colour black { 0xff000000 }; + const Colour blanchedalmond { 0xffffebcd }; + const Colour blue { 0xff0000ff }; + const Colour blueviolet { 0xff8a2be2 }; + const Colour brown { 0xffa52a2a }; + const Colour burlywood { 0xffdeb887 }; + const Colour cadetblue { 0xff5f9ea0 }; + const Colour chartreuse { 0xff7fff00 }; + const Colour chocolate { 0xffd2691e }; + const Colour coral { 0xffff7f50 }; + const Colour cornflowerblue { 0xff6495ed }; + const Colour cornsilk { 0xfffff8dc }; + const Colour crimson { 0xffdc143c }; + const Colour cyan { 0xff00ffff }; + const Colour darkblue { 0xff00008b }; + const Colour darkcyan { 0xff008b8b }; + const Colour darkgoldenrod { 0xffb8860b }; + const Colour darkgrey { 0xff555555 }; + const Colour darkgreen { 0xff006400 }; + const Colour darkkhaki { 0xffbdb76b }; + const Colour darkmagenta { 0xff8b008b }; + const Colour darkolivegreen { 0xff556b2f }; + const Colour darkorange { 0xffff8c00 }; + const Colour darkorchid { 0xff9932cc }; + const Colour darkred { 0xff8b0000 }; + const Colour darksalmon { 0xffe9967a }; + const Colour darkseagreen { 0xff8fbc8f }; + const Colour darkslateblue { 0xff483d8b }; + const Colour darkslategrey { 0xff2f4f4f }; + const Colour darkturquoise { 0xff00ced1 }; + const Colour darkviolet { 0xff9400d3 }; + const Colour deeppink { 0xffff1493 }; + const Colour deepskyblue { 0xff00bfff }; + const Colour dimgrey { 0xff696969 }; + const Colour dodgerblue { 0xff1e90ff }; + const Colour firebrick { 0xffb22222 }; + const Colour floralwhite { 0xfffffaf0 }; + const Colour forestgreen { 0xff228b22 }; + const Colour fuchsia { 0xffff00ff }; + const Colour gainsboro { 0xffdcdcdc }; + const Colour ghostwhite { 0xfff8f8ff }; + const Colour gold { 0xffffd700 }; + const Colour goldenrod { 0xffdaa520 }; + const Colour grey { 0xff808080 }; + const Colour green { 0xff008000 }; + const Colour greenyellow { 0xffadff2f }; + const Colour honeydew { 0xfff0fff0 }; + const Colour hotpink { 0xffff69b4 }; + const Colour indianred { 0xffcd5c5c }; + const Colour indigo { 0xff4b0082 }; + const Colour ivory { 0xfffffff0 }; + const Colour khaki { 0xfff0e68c }; + const Colour lavender { 0xffe6e6fa }; + const Colour lavenderblush { 0xfffff0f5 }; + const Colour lawngreen { 0xff7cfc00 }; + const Colour lemonchiffon { 0xfffffacd }; + const Colour lightblue { 0xffadd8e6 }; + const Colour lightcoral { 0xfff08080 }; + const Colour lightcyan { 0xffe0ffff }; + const Colour lightgoldenrodyellow { 0xfffafad2 }; + const Colour lightgreen { 0xff90ee90 }; + const Colour lightgrey { 0xffd3d3d3 }; + const Colour lightpink { 0xffffb6c1 }; + const Colour lightsalmon { 0xffffa07a }; + const Colour lightseagreen { 0xff20b2aa }; + const Colour lightskyblue { 0xff87cefa }; + const Colour lightslategrey { 0xff778899 }; + const Colour lightsteelblue { 0xffb0c4de }; + const Colour lightyellow { 0xffffffe0 }; + const Colour lime { 0xff00ff00 }; + const Colour limegreen { 0xff32cd32 }; + const Colour linen { 0xfffaf0e6 }; + const Colour magenta { 0xffff00ff }; + const Colour maroon { 0xff800000 }; + const Colour mediumaquamarine { 0xff66cdaa }; + const Colour mediumblue { 0xff0000cd }; + const Colour mediumorchid { 0xffba55d3 }; + const Colour mediumpurple { 0xff9370db }; + const Colour mediumseagreen { 0xff3cb371 }; + const Colour mediumslateblue { 0xff7b68ee }; + const Colour mediumspringgreen { 0xff00fa9a }; + const Colour mediumturquoise { 0xff48d1cc }; + const Colour mediumvioletred { 0xffc71585 }; + const Colour midnightblue { 0xff191970 }; + const Colour mintcream { 0xfff5fffa }; + const Colour mistyrose { 0xffffe4e1 }; + const Colour moccasin { 0xffffe4b5 }; + const Colour navajowhite { 0xffffdead }; + const Colour navy { 0xff000080 }; + const Colour oldlace { 0xfffdf5e6 }; + const Colour olive { 0xff808000 }; + const Colour olivedrab { 0xff6b8e23 }; + const Colour orange { 0xffffa500 }; + const Colour orangered { 0xffff4500 }; + const Colour orchid { 0xffda70d6 }; + const Colour palegoldenrod { 0xffeee8aa }; + const Colour palegreen { 0xff98fb98 }; + const Colour paleturquoise { 0xffafeeee }; + const Colour palevioletred { 0xffdb7093 }; + const Colour papayawhip { 0xffffefd5 }; + const Colour peachpuff { 0xffffdab9 }; + const Colour peru { 0xffcd853f }; + const Colour pink { 0xffffc0cb }; + const Colour plum { 0xffdda0dd }; + const Colour powderblue { 0xffb0e0e6 }; + const Colour purple { 0xff800080 }; + const Colour rebeccapurple { 0xff663399 }; + const Colour red { 0xffff0000 }; + const Colour rosybrown { 0xffbc8f8f }; + const Colour royalblue { 0xff4169e1 }; + const Colour saddlebrown { 0xff8b4513 }; + const Colour salmon { 0xfffa8072 }; + const Colour sandybrown { 0xfff4a460 }; + const Colour seagreen { 0xff2e8b57 }; + const Colour seashell { 0xfffff5ee }; + const Colour sienna { 0xffa0522d }; + const Colour silver { 0xffc0c0c0 }; + const Colour skyblue { 0xff87ceeb }; + const Colour slateblue { 0xff6a5acd }; + const Colour slategrey { 0xff708090 }; + const Colour snow { 0xfffffafa }; + const Colour springgreen { 0xff00ff7f }; + const Colour steelblue { 0xff4682b4 }; + const Colour tan { 0xffd2b48c }; + const Colour teal { 0xff008080 }; + const Colour thistle { 0xffd8bfd8 }; + const Colour tomato { 0xffff6347 }; + const Colour turquoise { 0xff40e0d0 }; + const Colour violet { 0xffee82ee }; + const Colour wheat { 0xfff5deb3 }; + const Colour white { 0xffffffff }; + const Colour whitesmoke { 0xfff5f5f5 }; + const Colour yellow { 0xffffff00 }; + const Colour yellowgreen { 0xff9acd32 }; /** Attempts to look up a string in the list of known colour names, and return the appropriate colour. @@ -96,16 +190,8 @@ public: if a match is found, that colour is returned. If no match is found, the colour passed in as the defaultColour parameter is returned. */ - static JUCE_API Colour findColourForName (const String& colourName, - Colour defaultColour); - -private: - //============================================================================== - // this isn't a class you should ever instantiate - it's just here for the - // static values in it. - Colours(); - - JUCE_DECLARE_NON_COPYABLE (Colours) -}; + JUCE_API Colour findColourForName (const String& colourName, + Colour defaultColour); +} // namespace Colours } // namespace juce diff --git a/modules/juce_graphics/contexts/juce_GraphicsContext.h b/modules/juce_graphics/contexts/juce_GraphicsContext.h index 95b5f257..e0563407 100644 --- a/modules/juce_graphics/contexts/juce_GraphicsContext.h +++ b/modules/juce_graphics/contexts/juce_GraphicsContext.h @@ -492,7 +492,7 @@ public: /** Draws part of an image, rescaling it to fit in a given target region. The specified area of the source image is rescaled and drawn to fill the - specifed destination rectangle. + specified destination rectangle. Images are composited using the context's current opacity, so if you don't want it to be drawn semi-transparently, be sure to call setOpacity (1.0f) diff --git a/modules/juce_graphics/fonts/juce_Font.h b/modules/juce_graphics/fonts/juce_Font.h index 91870c85..0b514738 100644 --- a/modules/juce_graphics/fonts/juce_Font.h +++ b/modules/juce_graphics/fonts/juce_Font.h @@ -134,7 +134,7 @@ public: This may also be set to Font::getDefaultSansSerifFontName(), Font::getDefaultSerifFontName(), or Font::getDefaultMonospacedFontName(), which are not actual platform-specific font family names, - but are generic font familiy names that are used to represent the various default fonts. + but are generic font family names that are used to represent the various default fonts. If you need to know the exact typeface font family being used, you can call Font::getTypeface()->getName(), which will give you the platform-specific font family. diff --git a/modules/juce_graphics/fonts/juce_GlyphArrangement.cpp b/modules/juce_graphics/fonts/juce_GlyphArrangement.cpp index de5c1dca..148c655e 100644 --- a/modules/juce_graphics/fonts/juce_GlyphArrangement.cpp +++ b/modules/juce_graphics/fonts/juce_GlyphArrangement.cpp @@ -711,7 +711,7 @@ void GlyphArrangement::draw (const Graphics& g, AffineTransform transform) const for (int i = 0; i < glyphs.size(); ++i) { - auto& pg = glyphs.getReference(i); + auto& pg = glyphs.getReference (i); if (pg.font.isUnderlined()) drawGlyphUnderline (g, pg, i, transform); diff --git a/modules/juce_graphics/fonts/juce_TextLayout.cpp b/modules/juce_graphics/fonts/juce_TextLayout.cpp index 8b2444cf..2cd8f78f 100644 --- a/modules/juce_graphics/fonts/juce_TextLayout.cpp +++ b/modules/juce_graphics/fonts/juce_TextLayout.cpp @@ -222,6 +222,8 @@ void TextLayout::draw (Graphics& g, Rectangle area) const auto origin = justification.appliedToRectangle (Rectangle (width, getHeight()), area).getPosition(); auto& context = g.getInternalContext(); + context.saveState(); + auto clip = context.getClipBounds(); auto clipTop = clip.getY() - origin.y; auto clipBottom = clip.getBottom() - origin.y; @@ -257,6 +259,8 @@ void TextLayout::draw (Graphics& g, Rectangle area) const } } } + + context.restoreState(); } void TextLayout::createLayout (const AttributedString& text, float maxWidth) diff --git a/modules/juce_graphics/fonts/juce_Typeface.h b/modules/juce_graphics/fonts/juce_Typeface.h index f1019a38..663c29c2 100644 --- a/modules/juce_graphics/fonts/juce_Typeface.h +++ b/modules/juce_graphics/fonts/juce_Typeface.h @@ -119,7 +119,7 @@ public: */ virtual bool getOutlineForGlyph (int glyphNumber, Path& path) = 0; - /** Returns a new EdgeTable that contains the path for the givem glyph, with the specified transform applied. */ + /** Returns a new EdgeTable that contains the path for the given glyph, with the specified transform applied. */ virtual EdgeTable* getEdgeTableForGlyph (int glyphNumber, const AffineTransform& transform, float fontHeight); /** Returns true if the typeface uses hinting. */ diff --git a/modules/juce_graphics/geometry/juce_AffineTransform.h b/modules/juce_graphics/geometry/juce_AffineTransform.h index 85427116..06452d49 100644 --- a/modules/juce_graphics/geometry/juce_AffineTransform.h +++ b/modules/juce_graphics/geometry/juce_AffineTransform.h @@ -270,7 +270,7 @@ public: */ float getScaleFactor() const noexcept; - /* A ready-to-use identity transform - now depracated. + /* A ready-to-use identity transform - now deprecated. @deprecated If you need an identity transform, just use AffineTransform() or {}. */ JUCE_DEPRECATED_STATIC (static const AffineTransform identity;) diff --git a/modules/juce_graphics/geometry/juce_Parallelogram.h b/modules/juce_graphics/geometry/juce_Parallelogram.h index e418dcf6..f55e38d1 100644 --- a/modules/juce_graphics/geometry/juce_Parallelogram.h +++ b/modules/juce_graphics/geometry/juce_Parallelogram.h @@ -162,7 +162,7 @@ public: + (bottomLeft - topLeft) * relativePosition.y; } - /** Returns a transformed verstion of the parallelogram. */ + /** Returns a transformed version of the parallelogram. */ Parallelogram transformedBy (const AffineTransform& transform) const noexcept { auto p = *this; diff --git a/modules/juce_graphics/geometry/juce_Path.h b/modules/juce_graphics/geometry/juce_Path.h index 73e728eb..e0cf526d 100644 --- a/modules/juce_graphics/geometry/juce_Path.h +++ b/modules/juce_graphics/geometry/juce_Path.h @@ -440,7 +440,7 @@ public: draw a curve clockwise from the 9 o'clock position to the 3 o'clock position via 12 o'clock, you'd use 1.5*Pi and 2.5*Pi as the start and finish points. @param startAsNewSubPath if true, the arc will begin a new subpath from its starting point; if false, - it will be added to the current sub-path, continuing from the current postition + it will be added to the current sub-path, continuing from the current position @see addCentredArc, arcTo, addPieSegment, addEllipse */ @@ -467,7 +467,7 @@ public: draw a curve clockwise from the 9 o'clock position to the 3 o'clock position via 12 o'clock, you'd use 1.5*Pi and 2.5*Pi as the start and finish points. @param startAsNewSubPath if true, the arc will begin a new subpath from its starting point; if false, - it will be added to the current sub-path, continuing from the current postition + it will be added to the current sub-path, continuing from the current position @see addArc, arcTo */ @@ -653,7 +653,7 @@ public: @param preserveProportions if true, it will fit the path into the space without altering its horizontal/vertical scale ratio; if false, it will distort the path to fill the specified ratio both horizontally and vertically - @param justificationType if the proportions are preseved, the resultant path may be smaller + @param justificationType if the proportions are preserved, the resultant path may be smaller than the available rectangle, so this describes how it should be positioned within the space. @returns an appropriate transformation @@ -671,7 +671,7 @@ public: @param preserveProportions if true, it will fit the path into the space without altering its horizontal/vertical scale ratio; if false, it will distort the path to fill the specified ratio both horizontally and vertically - @param justificationType if the proportions are preseved, the resultant path may be smaller + @param justificationType if the proportions are preserved, the resultant path may be smaller than the available rectangle, so this describes how it should be positioned within the space. @returns an appropriate transformation diff --git a/modules/juce_graphics/images/juce_Image.h b/modules/juce_graphics/images/juce_Image.h index 10d2c360..746a738b 100644 --- a/modules/juce_graphics/images/juce_Image.h +++ b/modules/juce_graphics/images/juce_Image.h @@ -336,13 +336,13 @@ public: /** Returns the colour of a given pixel. For performance reasons, this won't do any bounds-checking on the coordinates, so it's the caller's - repsonsibility to make sure they're within the image's size. + responsibility to make sure they're within the image's size. */ Colour getPixelColour (int x, int y) const noexcept; /** Sets the colour of a given pixel. For performance reasons, this won't do any bounds-checking on the coordinates, so it's the caller's - repsonsibility to make sure they're within the image's size. + responsibility to make sure they're within the image's size. */ void setPixelColour (int x, int y, Colour colour) const noexcept; diff --git a/modules/juce_graphics/images/juce_ImageConvolutionKernel.h b/modules/juce_graphics/images/juce_ImageConvolutionKernel.h index 84369580..8383ce40 100644 --- a/modules/juce_graphics/images/juce_ImageConvolutionKernel.h +++ b/modules/juce_graphics/images/juce_ImageConvolutionKernel.h @@ -39,7 +39,7 @@ class JUCE_API ImageConvolutionKernel { public: //============================================================================== - /** Creates an empty convulution kernel. + /** Creates an empty convolution kernel. @param size the length of each dimension of the kernel, so e.g. if the size is 5, it will create a 5x5 kernel @@ -73,7 +73,7 @@ public: /** Multiplies all values in the kernel by a value. */ void rescaleAllValues (float multiplier); - /** Intialises the kernel for a gaussian blur. + /** Initialises the kernel for a gaussian blur. @param blurRadius this may be larger or smaller than the kernel's actual size but this will obviously be wasteful or clip at the diff --git a/modules/juce_graphics/juce_graphics.h b/modules/juce_graphics/juce_graphics.h index 87d08424..39d8ca46 100644 --- a/modules/juce_graphics/juce_graphics.h +++ b/modules/juce_graphics/juce_graphics.h @@ -24,6 +24,7 @@ ============================================================================== */ + /******************************************************************************* The block below describes the properties of this module, and is read by the Projucer to automatically generate project code that uses it. @@ -33,18 +34,18 @@ BEGIN_JUCE_MODULE_DECLARATION - ID: juce_graphics - vendor: juce - version: 5.4.5 - name: JUCE graphics classes - description: Classes for 2D vector graphics, image loading/saving, font handling, etc. - website: http://www.juce.com/juce - license: GPL/Commercial - - dependencies: juce_events - OSXFrameworks: Cocoa QuartzCore - iOSFrameworks: CoreGraphics CoreImage CoreText QuartzCore - linuxPackages: x11 xinerama xext freetype2 + ID: juce_graphics + vendor: juce + version: 5.4.6 + name: JUCE graphics classes + description: Classes for 2D vector graphics, image loading/saving, font handling, etc. + website: http://www.juce.com/juce + license: GPL/Commercial + + dependencies: juce_events + OSXFrameworks: Cocoa QuartzCore + iOSFrameworks: CoreGraphics CoreImage CoreText QuartzCore + linuxPackages: x11 xinerama xext freetype2 END_JUCE_MODULE_DECLARATION diff --git a/modules/juce_graphics/native/juce_mac_CoreGraphicsContext.h b/modules/juce_graphics/native/juce_mac_CoreGraphicsContext.h index 02c69a5a..910304d4 100644 --- a/modules/juce_graphics/native/juce_mac_CoreGraphicsContext.h +++ b/modules/juce_graphics/native/juce_mac_CoreGraphicsContext.h @@ -93,7 +93,8 @@ private: FillType fillType; Font font; CGFontRef fontRef = {}; - AffineTransform fontTransform, inverseFontTransform; + CGAffineTransform textMatrix = CGAffineTransformIdentity, + inverseTextMatrix = CGAffineTransformIdentity; CGGradientRef gradient = {}; }; diff --git a/modules/juce_graphics/native/juce_mac_CoreGraphicsContext.mm b/modules/juce_graphics/native/juce_mac_CoreGraphicsContext.mm index f34002a6..3f87574e 100644 --- a/modules/juce_graphics/native/juce_mac_CoreGraphicsContext.mm +++ b/modules/juce_graphics/native/juce_mac_CoreGraphicsContext.mm @@ -28,10 +28,13 @@ namespace juce { //============================================================================== -class CoreGraphicsImage : public ImagePixelData +// This class has been renamed from CoreGraphicsImage to avoid a symbol +// collision in Pro Tools 2019.12 and possibly 2020 depending on the Pro Tools +// release schedule. +class CoreGraphicsPixelData : public ImagePixelData { public: - CoreGraphicsImage (const Image::PixelFormat format, int w, int h, bool clearImage) + CoreGraphicsPixelData (const Image::PixelFormat format, int w, int h, bool clearImage) : ImagePixelData (format, w, h) { pixelStride = format == Image::RGB ? 3 : ((format == Image::ARGB) ? 4 : 1); @@ -57,7 +60,7 @@ public: CGColorSpaceRelease (colourSpace); } - ~CoreGraphicsImage() override + ~CoreGraphicsPixelData() override { freeCachedImageRef(); CGContextRelease (context); @@ -86,7 +89,7 @@ public: ImagePixelData::Ptr clone() override { - auto im = new CoreGraphicsImage (pixelFormat, width, height, false); + auto im = new CoreGraphicsPixelData (pixelFormat, width, height, false); memcpy (im->imageDataHolder->data, imageDataHolder->data, (size_t) (lineStride * height)); return *im; } @@ -96,7 +99,7 @@ public: //============================================================================== static CGImageRef getCachedImageRef (const Image& juceImage, CGColorSpaceRef colourSpace) { - auto cgim = dynamic_cast (juceImage.getPixelData()); + auto cgim = dynamic_cast (juceImage.getPixelData()); if (cgim != nullptr && cgim->cachedImageRef != nullptr) { @@ -127,7 +130,7 @@ public: { auto* imageDataContainer = [](const Image& img) -> HeapBlockContainer::Ptr* { - if (auto* cgim = dynamic_cast (img.getPixelData())) + if (auto* cgim = dynamic_cast (img.getPixelData())) return new HeapBlockContainer::Ptr (cgim->imageDataHolder); return nullptr; @@ -183,12 +186,12 @@ private: #endif } - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CoreGraphicsImage) + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CoreGraphicsPixelData) }; ImagePixelData::Ptr NativeImageType::create (Image::PixelFormat format, int width, int height, bool clearImage) const { - return *new CoreGraphicsImage (format == Image::RGB ? Image::ARGB : format, width, height, clearImage); + return *new CoreGraphicsPixelData (format == Image::RGB ? Image::ARGB : format, width, height, clearImage); } //============================================================================== @@ -326,7 +329,7 @@ void CoreGraphicsContext::clipToImageAlpha (const Image& sourceImage, const Affi if (sourceImage.getFormat() != Image::SingleChannel) singleChannelImage = sourceImage.convertedToFormat (Image::SingleChannel); - CGImageRef image = CoreGraphicsImage::createImage (singleChannelImage, greyColourSpace, true); + CGImageRef image = CoreGraphicsPixelData::createImage (singleChannelImage, greyColourSpace, true); flip(); auto t = AffineTransform::verticalFlip (sourceImage.getHeight()).followedBy (transform); @@ -383,6 +386,8 @@ void CoreGraphicsContext::restoreState() if (auto* top = stateStack.getLast()) { state.reset (top); + CGContextSetTextMatrix (context, state->textMatrix); + stateStack.removeLast (1, false); lastClipRectIsValid = false; } @@ -522,7 +527,7 @@ void CoreGraphicsContext::drawImage (const Image& sourceImage, const AffineTrans auto colourSpace = sourceImage.getFormat() == Image::PixelFormat::SingleChannel ? greyColourSpace : rgbColourSpace; - CGImageRef image = CoreGraphicsImage::getCachedImageRef (sourceImage, colourSpace); + CGImageRef image = CoreGraphicsPixelData::getCachedImageRef (sourceImage, colourSpace); CGContextSaveGState (context); CGContextSetAlpha (context, state->fillType.getOpacity()); @@ -623,20 +628,11 @@ void CoreGraphicsContext::setFont (const Font& newFont) CGContextSetFont (context, state->fontRef); CGContextSetFontSize (context, state->font.getHeight() * osxTypeface->fontHeightToPointsFactor); - auto fontTransform = osxTypeface->renderingTransform; - fontTransform.a *= state->font.getHorizontalScale(); - CGContextSetTextMatrix (context, fontTransform); - - auto cgTransformToJuceTransform = [](CGAffineTransform& t) -> AffineTransform - { - return { (float) t.a, (float) t.c, (float) t.tx, - (float) t.b, (float) t.d, (float) t.ty }; - }; - - state->fontTransform = cgTransformToJuceTransform (fontTransform); - auto inverseFontTransform = CGAffineTransformInvert (fontTransform); - state->inverseFontTransform = cgTransformToJuceTransform (inverseFontTransform); - } + state->textMatrix = osxTypeface->renderingTransform; + state->textMatrix.a *= state->font.getHorizontalScale(); + CGContextSetTextMatrix (context, state->textMatrix); + state->inverseTextMatrix = CGAffineTransformInvert (state->textMatrix); + } } } @@ -649,12 +645,18 @@ void CoreGraphicsContext::drawGlyph (int glyphNumber, const AffineTransform& tra { if (state->fontRef != nullptr && state->fillType.isColour()) { - if (transform.isOnlyTranslation() && state->fontTransform.isOnlyTranslation()) + auto cgTransformIsOnlyTranslation = [](CGAffineTransform t) + { + return t.a == 1.0f && t.d == 1.0f && t.b == 0.0f && t.c == 0.0f; + }; + + if (transform.isOnlyTranslation() && cgTransformIsOnlyTranslation (state->inverseTextMatrix)) { - auto t = transform.followedBy (state->inverseFontTransform); + auto x = transform.mat02 + state->inverseTextMatrix.tx; + auto y = transform.mat12 + state->inverseTextMatrix.ty; CGGlyph glyphs[1] = { (CGGlyph) glyphNumber }; - CGPoint positions[1] = { { t.getTranslationX(), flipHeight - roundToInt (t.getTranslationY()) } }; + CGPoint positions[1] = { { x, flipHeight - roundToInt (y) } }; CGContextShowGlyphsAtPositions (context, glyphs, positions, 1); } else @@ -662,9 +664,11 @@ void CoreGraphicsContext::drawGlyph (int glyphNumber, const AffineTransform& tra CGContextSaveGState (context); flip(); - auto fontTransform = state->fontTransform; - fontTransform.mat11 = -fontTransform.mat11; - applyTransform (fontTransform.followedBy (state->inverseFontTransform).followedBy (transform)); + applyTransform (transform); + CGContextConcatCTM (context, state->inverseTextMatrix); + auto cgTransform = state->textMatrix; + cgTransform.d = -cgTransform.d; + CGContextConcatCTM (context, cgTransform); CGGlyph glyphs[1] = { (CGGlyph) glyphNumber }; CGPoint positions[1] = { { 0.0f, 0.0f } }; @@ -697,8 +701,7 @@ CoreGraphicsContext::SavedState::SavedState() CoreGraphicsContext::SavedState::SavedState (const SavedState& other) : fillType (other.fillType), font (other.font), fontRef (other.fontRef), - fontTransform (other.fontTransform), - inverseFontTransform (other.inverseFontTransform), + textMatrix (other.textMatrix), inverseTextMatrix (other.inverseTextMatrix), gradient (other.gradient) { if (gradient != nullptr) @@ -887,8 +890,8 @@ Image juce_loadWithCoreImage (InputStream& input) (int) CGImageGetHeight (loadedImage), hasAlphaChan)); - auto cgImage = dynamic_cast (image.getPixelData()); - jassert (cgImage != nullptr); // if USE_COREGRAPHICS_RENDERING is set, the CoreGraphicsImage class should have been used. + auto cgImage = dynamic_cast (image.getPixelData()); + jassert (cgImage != nullptr); // if USE_COREGRAPHICS_RENDERING is set, the CoreGraphicsPixelData class should have been used. CGContextDrawImage (cgImage->context, convertToCGRect (image.getBounds()), loadedImage); CGContextFlush (cgImage->context); @@ -912,7 +915,7 @@ Image juce_loadWithCoreImage (InputStream& input) Image juce_createImageFromCIImage (CIImage*, int, int); Image juce_createImageFromCIImage (CIImage* im, int w, int h) { - auto cgImage = new CoreGraphicsImage (Image::ARGB, w, h, false); + auto cgImage = new CoreGraphicsPixelData (Image::ARGB, w, h, false); CIContext* cic = [CIContext contextWithCGContext: cgImage->context options: nil]; [cic drawImage: im inRect: CGRectMake (0, 0, w, h) fromRect: CGRectMake (0, 0, w, h)]; @@ -924,12 +927,12 @@ Image juce_createImageFromCIImage (CIImage* im, int w, int h) CGImageRef juce_createCoreGraphicsImage (const Image& juceImage, CGColorSpaceRef colourSpace, const bool mustOutliveSource) { - return CoreGraphicsImage::createImage (juceImage, colourSpace, mustOutliveSource); + return CoreGraphicsPixelData::createImage (juceImage, colourSpace, mustOutliveSource); } CGContextRef juce_getImageContext (const Image& image) { - if (auto cgi = dynamic_cast (image.getPixelData())) + if (auto cgi = dynamic_cast (image.getPixelData())) return cgi->context; jassertfalse; diff --git a/modules/juce_graphics/native/juce_mac_Fonts.mm b/modules/juce_graphics/native/juce_mac_Fonts.mm index 6ae7035d..12b4e25d 100644 --- a/modules/juce_graphics/native/juce_mac_Fonts.mm +++ b/modules/juce_graphics/native/juce_mac_Fonts.mm @@ -276,10 +276,10 @@ namespace CoreTextTypeLayout CTParagraphStyleSetting settings[] = { - { kCTParagraphStyleSpecifierAlignment, sizeof (CTTextAlignment), &ctTextAlignment }, - { kCTParagraphStyleSpecifierLineBreakMode, sizeof (CTLineBreakMode), &ctLineBreakMode }, + { kCTParagraphStyleSpecifierAlignment, sizeof (CTTextAlignment), &ctTextAlignment }, + { kCTParagraphStyleSpecifierLineBreakMode, sizeof (CTLineBreakMode), &ctLineBreakMode }, { kCTParagraphStyleSpecifierBaseWritingDirection, sizeof (CTWritingDirection), &ctWritingDirection}, - { kCTParagraphStyleSpecifierLineSpacingAdjustment, sizeof (CGFloat), &ctLineSpacing } + { kCTParagraphStyleSpecifierLineSpacingAdjustment, sizeof (CGFloat), &ctLineSpacing } }; auto ctParagraphStyleRef = CTParagraphStyleCreate (settings, (size_t) numElementsInArray (settings)); @@ -292,22 +292,35 @@ namespace CoreTextTypeLayout return attribString; } - static CTFrameRef createCTFrame (const AttributedString& text, CGRect bounds) + static CTFramesetterRef createCTFramesetter (const AttributedString& text) { auto attribString = createCFAttributedString (text); auto framesetter = CTFramesetterCreateWithAttributedString (attribString); CFRelease (attribString); + return framesetter; + } + + static CTFrameRef createCTFrame (CTFramesetterRef framesetter, CGRect bounds) + { auto path = CGPathCreateMutable(); CGPathAddRect (path, nullptr, bounds); auto frame = CTFramesetterCreateFrame (framesetter, CFRangeMake (0, 0), path, nullptr); - CFRelease (framesetter); CGPathRelease (path); return frame; } + static CTFrameRef createCTFrame (const AttributedString& text, CGRect bounds) + { + auto framesetter = createCTFramesetter (text); + auto frame = createCTFrame (framesetter, bounds); + CFRelease (framesetter); + + return frame; + } + static Range getLineVerticalRange (CTFrameRef frame, CFArrayRef lines, int lineIndex) { LineInfo info (frame, (CTLineRef) CFArrayGetValueAtIndex (lines, lineIndex), lineIndex); @@ -335,39 +348,58 @@ namespace CoreTextTypeLayout static void drawToCGContext (const AttributedString& text, const Rectangle& area, const CGContextRef& context, float flipHeight) { - Rectangle ctFrameArea; - auto verticalJustification = text.getJustification().getOnlyVerticalFlags(); + auto framesetter = createCTFramesetter (text); // Ugly hack to fix a bug in OS X Sierra where the CTFrame needs to be slightly // larger than the font height - otherwise the CTFrame will be invalid - if (verticalJustification == Justification::verticallyCentred) - ctFrameArea = area.withSizeKeepingCentre (area.getWidth(), area.getHeight() * 1.1f); - else if (verticalJustification == Justification::bottom) - ctFrameArea = area.withTop (area.getY() - (area.getHeight() * 0.1f)); - else - ctFrameArea = area.withHeight (area.getHeight() * 1.1f); - auto frame = createCTFrame (text, CGRectMake ((CGFloat) ctFrameArea.getX(), flipHeight - (CGFloat) ctFrameArea.getBottom(), - (CGFloat) ctFrameArea.getWidth(), (CGFloat) ctFrameArea.getHeight())); + CFRange fitrange; + auto suggestedSingleLineFrameSize = + CTFramesetterSuggestFrameSizeWithConstraints (framesetter, CFRangeMake (0, 0), nullptr, + CGSizeMake (CGFLOAT_MAX, CGFLOAT_MAX), &fitrange); + auto minCTFrameHeight = (float) suggestedSingleLineFrameSize.height; + + auto verticalJustification = text.getJustification().getOnlyVerticalFlags(); + + auto ctFrameArea = [area, minCTFrameHeight, verticalJustification] + { + if (minCTFrameHeight < area.getHeight()) + return area; + + if (verticalJustification == Justification::verticallyCentred) + return area.withSizeKeepingCentre (area.getWidth(), minCTFrameHeight); + + auto frameArea = area.withHeight (minCTFrameHeight); + + if (verticalJustification == Justification::bottom) + return frameArea.withBottomY (area.getBottom()); + + return frameArea; + }(); + + auto frame = createCTFrame (framesetter, CGRectMake ((CGFloat) ctFrameArea.getX(), flipHeight - (CGFloat) ctFrameArea.getBottom(), + (CGFloat) ctFrameArea.getWidth(), (CGFloat) ctFrameArea.getHeight())); + CFRelease (framesetter); + + auto textMatrix = CGContextGetTextMatrix (context); + CGContextSaveGState (context); if (verticalJustification == Justification::verticallyCentred - || verticalJustification == Justification::bottom) + || verticalJustification == Justification::bottom) { auto adjust = ctFrameArea.getHeight() - findCTFrameHeight (frame); if (verticalJustification == Justification::verticallyCentred) adjust *= 0.5f; - CGContextSaveGState (context); CGContextTranslateCTM (context, 0, -adjust); - CTFrameDraw (frame, context); - CGContextRestoreGState (context); - } - else - { - CTFrameDraw (frame, context); } + CTFrameDraw (frame, context); + + CGContextRestoreGState (context); + CGContextSetTextMatrix (context, textMatrix); + CFRelease (frame); } diff --git a/modules/juce_graphics/native/juce_win32_Direct2DGraphicsContext.cpp b/modules/juce_graphics/native/juce_win32_Direct2DGraphicsContext.cpp index 75a58b90..3913247b 100644 --- a/modules/juce_graphics/native/juce_win32_Direct2DGraphicsContext.cpp +++ b/modules/juce_graphics/native/juce_win32_Direct2DGraphicsContext.cpp @@ -30,12 +30,12 @@ namespace juce template D2D1_RECT_F rectangleToRectF (const Rectangle& r) { - return D2D1::RectF ((float) r.getX(), (float) r.getY(), (float) r.getRight(), (float) r.getBottom()); + return { (float) r.getX(), (float) r.getY(), (float) r.getRight(), (float) r.getBottom() }; } static D2D1_COLOR_F colourToD2D (Colour c) { - return D2D1::ColorF::ColorF (c.getFloatRed(), c.getFloatGreen(), c.getFloatBlue(), c.getFloatAlpha()); + return { c.getFloatRed(), c.getFloatGreen(), c.getFloatBlue(), c.getFloatAlpha() }; } static void pathToGeometrySink (const Path& path, ID2D1GeometrySink* sink, const AffineTransform& transform) @@ -48,39 +48,26 @@ static void pathToGeometrySink (const Path& path, ID2D1GeometrySink* sink, const { case Path::Iterator::cubicTo: { - D2D1_BEZIER_SEGMENT seg; + transform.transformPoint (it.x1, it.y1); + transform.transformPoint (it.x2, it.y2); + transform.transformPoint (it.x3, it.y3); - transform.transformPoint (it.x1, it.y1); - seg.point1 = D2D1::Point2F (it.x1, it.y1); - - transform.transformPoint (it.x2, it.y2); - seg.point2 = D2D1::Point2F (it.x2, it.y2); - - transform.transformPoint (it.x3, it.y3); - seg.point3 = D2D1::Point2F (it.x3, it.y3); - - sink->AddBezier (seg); + sink->AddBezier ({ { it.x1, it.y1 }, { it.x2, it.y2 }, { it.x3, it.y3 } }); break; } case Path::Iterator::lineTo: { - transform.transformPoint (it.x1, it.y1); - sink->AddLine (D2D1::Point2F (it.x1, it.y1)); + transform.transformPoint (it.x1, it.y1); + sink->AddLine ({ it.x1, it.y1 }); break; } case Path::Iterator::quadraticTo: { - D2D1_QUADRATIC_BEZIER_SEGMENT seg; - - transform.transformPoint (it.x1, it.y1); - seg.point1 = D2D1::Point2F (it.x1, it.y1); - - transform.transformPoint (it.x2, it.y2); - seg.point2 = D2D1::Point2F (it.x2, it.y2); - - sink->AddQuadraticBezier (seg); + transform.transformPoint (it.x1, it.y1); + transform.transformPoint (it.x2, it.y2); + sink->AddQuadraticBezier ({ { it.x1, it.y1 }, { it.x2, it.y2 } }); break; } @@ -92,8 +79,8 @@ static void pathToGeometrySink (const Path& path, ID2D1GeometrySink* sink, const case Path::Iterator::startNewSubPath: { - transform.transformPoint (it.x1, it.y1); - sink->BeginFigure (D2D1::Point2F (it.x1, it.y1), D2D1_FIGURE_BEGIN_FILLED); + transform.transformPoint (it.x1, it.y1); + sink->BeginFigure ({ it.x1, it.y1 }, D2D1_FIGURE_BEGIN_FILLED); break; } } @@ -102,20 +89,13 @@ static void pathToGeometrySink (const Path& path, ID2D1GeometrySink* sink, const static D2D1::Matrix3x2F transformToMatrix (const AffineTransform& transform) { - D2D1::Matrix3x2F matrix; - matrix._11 = transform.mat00; - matrix._12 = transform.mat10; - matrix._21 = transform.mat01; - matrix._22 = transform.mat11; - matrix._31 = transform.mat02; - matrix._32 = transform.mat12; - return matrix; + return { transform.mat00, transform.mat10, transform.mat01, transform.mat11, transform.mat02, transform.mat12 }; } static D2D1_POINT_2F pointTransformed (int x, int y, const AffineTransform& transform) { transform.transformPoint (x, y); - return D2D1::Point2F ((FLOAT) x, (FLOAT) y); + return { (FLOAT) x, (FLOAT) y }; } static void rectToGeometrySink (const Rectangle& rect, ID2D1GeometrySink* sink, const AffineTransform& transform) @@ -136,7 +116,7 @@ struct Direct2DLowLevelGraphicsContext::Pimpl factories->d2dFactory->CreatePathGeometry (&p); ComSmartPtr sink; - HRESULT hr = p->Open (sink.resetAndGetPointerAddress()); // xxx handle error + auto hr = p->Open (sink.resetAndGetPointerAddress()); // xxx handle error sink->SetFillMode (D2D1_FILL_MODE_WINDING); for (int i = clipRegion.getNumRectangles(); --i >= 0;) @@ -152,7 +132,7 @@ struct Direct2DLowLevelGraphicsContext::Pimpl factories->d2dFactory->CreatePathGeometry (&p); ComSmartPtr sink; - HRESULT hr = p->Open (sink.resetAndGetPointerAddress()); + auto hr = p->Open (sink.resetAndGetPointerAddress()); sink->SetFillMode (D2D1_FILL_MODE_WINDING); // xxx need to check Path::isUsingNonZeroWinding() pathToGeometrySink (path, sink, transform); @@ -188,7 +168,7 @@ public: } else { - const D2D1_SIZE_U size (owner.pimpl->renderingTarget->GetPixelSize()); + const auto size = owner.pimpl->renderingTarget->GetPixelSize(); clipRect.setSize (size.width, size.height); setFill (FillType (Colours::black)); } @@ -214,7 +194,7 @@ public: void clipToRectangle (const Rectangle& r) { clearClip(); - clipRect = r.toFloat().transformed (transform).getSmallestIntegerContainer(); + clipRect = r.toFloat().transformedBy (transform).getSmallestIntegerContainer(); shouldClipRect = true; pushClips(); } @@ -284,24 +264,17 @@ public: if (bitmapMaskLayer == nullptr) owner.pimpl->renderingTarget->CreateLayer (bitmapMaskLayer.resetAndGetPointerAddress()); - D2D1_BRUSH_PROPERTIES brushProps; - brushProps.opacity = 1; - brushProps.transform = transformToMatrix (clipTransform); - - D2D1_BITMAP_BRUSH_PROPERTIES bmProps = D2D1::BitmapBrushProperties (D2D1_EXTEND_MODE_WRAP, D2D1_EXTEND_MODE_WRAP); - - D2D1_SIZE_U size; - size.width = clipImage.getWidth(); - size.height = clipImage.getHeight(); - - D2D1_BITMAP_PROPERTIES bp = D2D1::BitmapProperties(); + D2D1_BRUSH_PROPERTIES brushProps = { 1, transformToMatrix (clipTransform) }; + auto bmProps = D2D1::BitmapBrushProperties (D2D1_EXTEND_MODE_WRAP, D2D1_EXTEND_MODE_WRAP); + D2D1_SIZE_U size = { (UINT32) clipImage.getWidth(), (UINT32) clipImage.getHeight() }; + auto bp = D2D1::BitmapProperties(); maskImage = clipImage.convertedToFormat (Image::ARGB); Image::BitmapData bd (maskImage, Image::BitmapData::readOnly); // xxx should be maskImage? bp.pixelFormat = owner.pimpl->renderingTarget->GetPixelFormat(); bp.pixelFormat.alphaMode = D2D1_ALPHA_MODE_PREMULTIPLIED; - HRESULT hr = owner.pimpl->renderingTarget->CreateBitmap (size, bd.data, bd.lineStride, bp, maskBitmap.resetAndGetPointerAddress()); + auto hr = owner.pimpl->renderingTarget->CreateBitmap (size, bd.data, bd.lineStride, bp, maskBitmap.resetAndGetPointerAddress()); hr = owner.pimpl->renderingTarget->CreateBitmapBrush (maskBitmap, bmProps, brushProps, bitmapMaskBrush.resetAndGetPointerAddress()); imageMaskLayerParams = D2D1::LayerParameters(); @@ -348,7 +321,7 @@ public: if (shouldClipRectList && !clipsRectList) { - D2D1_LAYER_PARAMETERS layerParams = D2D1::LayerParameters(); + auto layerParams = D2D1::LayerParameters(); rectListGeometry->GetBounds (D2D1::IdentityMatrix(), &layerParams.contentBounds); layerParams.geometricMask = rectListGeometry; owner.pimpl->renderingTarget->PushLayer (layerParams, rectListLayer); @@ -357,7 +330,7 @@ public: if (shouldClipComplex && !clipsComplex) { - D2D1_LAYER_PARAMETERS layerParams = D2D1::LayerParameters(); + auto layerParams = D2D1::LayerParameters(); complexClipGeometry->GetBounds (D2D1::IdentityMatrix(), &layerParams.contentBounds); layerParams.geometricMask = complexClipGeometry; owner.pimpl->renderingTarget->PushLayer (layerParams, complexClipLayer); @@ -398,7 +371,7 @@ public: { if (currentFontFace == nullptr) { - WindowsDirectWriteTypeface* typeface = dynamic_cast (font.getTypeface()); + auto* typeface = dynamic_cast (font.getTypeface()); currentFontFace = typeface->getIDWriteFontFace(); fontHeightToEmSizeFactor = typeface->getUnitsToHeightScaleFactor(); } @@ -428,32 +401,26 @@ public: { if (fillType.isColour()) { - D2D1_COLOR_F colour = colourToD2D (fillType.colour); + auto colour = colourToD2D (fillType.colour); owner.pimpl->colourBrush->SetColor (colour); currentBrush = owner.pimpl->colourBrush; } else if (fillType.isTiledImage()) { - D2D1_BRUSH_PROPERTIES brushProps; - brushProps.opacity = fillType.getOpacity(); - brushProps.transform = transformToMatrix (fillType.transform); - - D2D1_BITMAP_BRUSH_PROPERTIES bmProps = D2D1::BitmapBrushProperties (D2D1_EXTEND_MODE_WRAP, D2D1_EXTEND_MODE_WRAP); + D2D1_BRUSH_PROPERTIES brushProps = { fillType.getOpacity(), transformToMatrix (fillType.transform) }; + auto bmProps = D2D1::BitmapBrushProperties (D2D1_EXTEND_MODE_WRAP, D2D1_EXTEND_MODE_WRAP); image = fillType.image; - D2D1_SIZE_U size; - size.width = image.getWidth(); - size.height = image.getHeight(); - - D2D1_BITMAP_PROPERTIES bp = D2D1::BitmapProperties(); + D2D1_SIZE_U size = { (UINT32) image.getWidth(), (UINT32) image.getHeight() }; + auto bp = D2D1::BitmapProperties(); this->image = image.convertedToFormat (Image::ARGB); Image::BitmapData bd (this->image, Image::BitmapData::readOnly); bp.pixelFormat = owner.pimpl->renderingTarget->GetPixelFormat(); bp.pixelFormat.alphaMode = D2D1_ALPHA_MODE_PREMULTIPLIED; - HRESULT hr = owner.pimpl->renderingTarget->CreateBitmap (size, bd.data, bd.lineStride, bp, bitmap.resetAndGetPointerAddress()); + auto hr = owner.pimpl->renderingTarget->CreateBitmap (size, bd.data, bd.lineStride, bp, bitmap.resetAndGetPointerAddress()); hr = owner.pimpl->renderingTarget->CreateBitmapBrush (bitmap, bmProps, brushProps, bitmapBrush.resetAndGetPointerAddress()); currentBrush = bitmapBrush; @@ -462,9 +429,7 @@ public: { gradientStops = nullptr; - D2D1_BRUSH_PROPERTIES brushProps; - brushProps.opacity = fillType.getOpacity(); - brushProps.transform = transformToMatrix (fillType.transform.followedBy (transform)); + D2D1_BRUSH_PROPERTIES brushProps = { fillType.getOpacity(), transformToMatrix (fillType.transform.followedBy (transform)) }; const int numColors = fillType.gradient->getNumColours(); @@ -482,28 +447,21 @@ public: { radialGradient = nullptr; - const Point p1 = fillType.gradient->point1; - const Point p2 = fillType.gradient->point2; - float r = p1.getDistanceFrom(p2); - - D2D1_RADIAL_GRADIENT_BRUSH_PROPERTIES props = - D2D1::RadialGradientBrushProperties(D2D1::Point2F(p1.x, p1.y), - D2D1::Point2F(0, 0), - r, r); + const auto p1 = fillType.gradient->point1; + const auto p2 = fillType.gradient->point2; + const auto r = p1.getDistanceFrom(p2); + const auto props = D2D1::RadialGradientBrushProperties ({ p1.x, p1.y }, {}, r, r); - owner.pimpl->renderingTarget->CreateRadialGradientBrush(props, brushProps, gradientStops, radialGradient.resetAndGetPointerAddress()); + owner.pimpl->renderingTarget->CreateRadialGradientBrush (props, brushProps, gradientStops, radialGradient.resetAndGetPointerAddress()); currentBrush = radialGradient; } else { linearGradient = 0; - const Point p1 = fillType.gradient->point1; - const Point p2 = fillType.gradient->point2; - - D2D1_LINEAR_GRADIENT_BRUSH_PROPERTIES props = - D2D1::LinearGradientBrushProperties(D2D1::Point2F(p1.x, p1.y), - D2D1::Point2F(p2.x, p2.y)); + const auto p1 = fillType.gradient->point1; + const auto p2 = fillType.gradient->point2; + const auto props = D2D1::LinearGradientBrushProperties ({ p1.x, p1.y }, { p2.x, p2.y }); owner.pimpl->renderingTarget->CreateLinearGradientBrush (props, brushProps, gradientStops, linearGradient.resetAndGetPointerAddress()); @@ -518,7 +476,7 @@ public: AffineTransform transform; Font font; - float fontHeightToEmSizeFactor = 1.0; + float fontHeightToEmSizeFactor = 1.0f; IDWriteFontFace* currentFontFace = nullptr; ComSmartPtr localFontFace; @@ -568,12 +526,9 @@ Direct2DLowLevelGraphicsContext::Direct2DLowLevelGraphicsContext (HWND hwnd_) D2D1_SIZE_U size = { (UINT32) (windowRect.right - windowRect.left), (UINT32) (windowRect.bottom - windowRect.top) }; bounds.setSize (size.width, size.height); - D2D1_RENDER_TARGET_PROPERTIES props = D2D1::RenderTargetProperties(); - D2D1_HWND_RENDER_TARGET_PROPERTIES propsHwnd = D2D1::HwndRenderTargetProperties (hwnd, size); - if (pimpl->factories->d2dFactory != nullptr) { - HRESULT hr = pimpl->factories->d2dFactory->CreateHwndRenderTarget (props, propsHwnd, pimpl->renderingTarget.resetAndGetPointerAddress()); + auto hr = pimpl->factories->d2dFactory->CreateHwndRenderTarget ({}, { hwnd, size }, pimpl->renderingTarget.resetAndGetPointerAddress()); jassert (SUCCEEDED (hr)); ignoreUnused (hr); hr = pimpl->renderingTarget->CreateSolidColorBrush (D2D1::ColorF::ColorF (0.0f, 0.0f, 0.0f, 1.0f), pimpl->colourBrush.resetAndGetPointerAddress()); } @@ -608,7 +563,7 @@ void Direct2DLowLevelGraphicsContext::start() void Direct2DLowLevelGraphicsContext::end() { states.clear(); - currentState = 0; + currentState = nullptr; pimpl->renderingTarget->EndDraw(); pimpl->renderingTarget->CheckWindowState(); } @@ -657,13 +612,13 @@ void Direct2DLowLevelGraphicsContext::clipToImageAlpha (const Image& sourceImage bool Direct2DLowLevelGraphicsContext::clipRegionIntersects (const Rectangle& r) { - return currentState->clipRect.intersects (r.toFloat().transformed (currentState->transform).getSmallestIntegerContainer()); + return currentState->clipRect.intersects (r.toFloat().transformedBy (currentState->transform).getSmallestIntegerContainer()); } Rectangle Direct2DLowLevelGraphicsContext::getClipBounds() const { // xxx could this take into account complex clip regions? - return currentState->clipRect.toFloat().transformed (currentState->transform.inverted()).getSmallestIntegerContainer(); + return currentState->clipRect.toFloat().transformedBy (currentState->transform.inverted()).getSmallestIntegerContainer(); } bool Direct2DLowLevelGraphicsContext::isClipEmpty() const @@ -679,7 +634,7 @@ void Direct2DLowLevelGraphicsContext::saveState() void Direct2DLowLevelGraphicsContext::restoreState() { - jassert (states.size() > 1); //you should never pop the last state! + jassert (states.size() > 1); //you should never pop the last state! states.removeLast (1); currentState = states.getLast(); } @@ -740,11 +695,8 @@ void Direct2DLowLevelGraphicsContext::drawImage (const Image& image, const Affin { pimpl->renderingTarget->SetTransform (transformToMatrix (transform.followedBy (currentState->transform))); - D2D1_SIZE_U size; - size.width = image.getWidth(); - size.height = image.getHeight(); - - D2D1_BITMAP_PROPERTIES bp = D2D1::BitmapProperties(); + D2D1_SIZE_U size = { (UINT32) image.getWidth(), (UINT32) image.getHeight() }; + auto bp = D2D1::BitmapProperties(); Image img (image.convertedToFormat (Image::ARGB)); Image::BitmapData bd (img, Image::BitmapData::readOnly); @@ -788,17 +740,15 @@ void Direct2DLowLevelGraphicsContext::drawGlyph (int glyphNumber, const AffineTr currentState->createBrush(); currentState->createFont(); - float hScale = currentState->font.getHorizontalScale(); + auto hScale = currentState->font.getHorizontalScale(); pimpl->renderingTarget->SetTransform (transformToMatrix (AffineTransform::scale (hScale, 1.0f) .followedBy (transform) .followedBy (currentState->transform))); - const UINT16 glyphIndices = (UINT16) glyphNumber; - const FLOAT glyphAdvances = 0; - DWRITE_GLYPH_OFFSET offset; - offset.advanceOffset = 0; - offset.ascenderOffset = 0; + const auto glyphIndices = (UINT16) glyphNumber; + const auto glyphAdvances = 0.0f; + DWRITE_GLYPH_OFFSET offset = { 0.0f, 0.0f }; DWRITE_GLYPH_RUN glyphRun; glyphRun.fontFace = currentState->currentFontFace; @@ -810,7 +760,7 @@ void Direct2DLowLevelGraphicsContext::drawGlyph (int glyphNumber, const AffineTr glyphRun.isSideways = FALSE; glyphRun.bidiLevel = 0; - pimpl->renderingTarget->DrawGlyphRun (D2D1::Point2F (0, 0), &glyphRun, currentState->currentBrush); + pimpl->renderingTarget->DrawGlyphRun ({}, &glyphRun, currentState->currentBrush); pimpl->renderingTarget->SetTransform (D2D1::IdentityMatrix()); } diff --git a/modules/juce_graphics/native/juce_win32_DirectWriteTypeLayout.cpp b/modules/juce_graphics/native/juce_win32_DirectWriteTypeLayout.cpp index ea2c6716..6e8facbc 100644 --- a/modules/juce_graphics/native/juce_win32_DirectWriteTypeLayout.cpp +++ b/modules/juce_graphics/native/juce_win32_DirectWriteTypeLayout.cpp @@ -218,6 +218,7 @@ namespace DirectWriteTypeLayout switch (text.getJustification().getOnlyHorizontalFlags()) { + case 0: case Justification::left: break; case Justification::right: alignment = DWRITE_TEXT_ALIGNMENT_TRAILING; break; case Justification::horizontallyCentred: alignment = DWRITE_TEXT_ALIGNMENT_CENTER; break; @@ -241,6 +242,7 @@ namespace DirectWriteTypeLayout switch (text.getJustification().getOnlyHorizontalFlags()) { + case 0: case Justification::left: alignment = DWRITE_TEXT_ALIGNMENT_TRAILING; break; case Justification::right: alignment = DWRITE_TEXT_ALIGNMENT_LEADING; break; default: break; @@ -301,7 +303,7 @@ namespace DirectWriteTypeLayout col.getFloatAlpha()), d2dBrush.resetAndGetPointerAddress()); - // We need to call SetDrawingEffect with a legimate brush to get DirectWrite to break text based on colours + // We need to call SetDrawingEffect with a legitimate brush to get DirectWrite to break text based on colours textLayout.SetDrawingEffect (d2dBrush, range); } } diff --git a/modules/juce_gui_basics/buttons/juce_TextButton.h b/modules/juce_gui_basics/buttons/juce_TextButton.h index b5811cbc..98ca4be7 100644 --- a/modules/juce_gui_basics/buttons/juce_TextButton.h +++ b/modules/juce_gui_basics/buttons/juce_TextButton.h @@ -54,7 +54,7 @@ public: @param buttonName the text to put in the button (the component's name is also initially set to this string, but these can be changed later using the setName() and setButtonText() methods) - @param toolTip an optional string to use as a toolip + @param toolTip an optional string to use as a tooltip */ TextButton (const String& buttonName, const String& toolTip); diff --git a/modules/juce_gui_basics/components/juce_Component.cpp b/modules/juce_gui_basics/components/juce_Component.cpp index 1a2106a4..d7734de4 100644 --- a/modules/juce_gui_basics/components/juce_Component.cpp +++ b/modules/juce_gui_basics/components/juce_Component.cpp @@ -1845,6 +1845,9 @@ void Component::internalRepaintUnchecked (Rectangle area, bool isEntireComp : cachedImage->invalidate (area))) return; + if (area.isEmpty()) + return; + if (flags.hasHeavyweightPeerFlag) { if (auto* peer = getPeer()) @@ -1899,12 +1902,10 @@ void Component::paintComponentAndChildren (Graphics& g) } else { - g.saveState(); + Graphics::ScopedSaveState ss (g); if (! (ComponentHelpers::clipObscuredRegions (*this, g, clipBounds, {}) && g.isClipEmpty())) paint (g); - - g.restoreState(); } for (int i = 0; i < childComponentList.size(); ++i) @@ -1915,17 +1916,16 @@ void Component::paintComponentAndChildren (Graphics& g) { if (child.affineTransform != nullptr) { - g.saveState(); + Graphics::ScopedSaveState ss (g); + g.addTransform (*child.affineTransform); if ((child.flags.dontClipGraphicsFlag && ! g.isClipEmpty()) || g.reduceClipRegion (child.getBounds())) child.paintWithinParentContext (g); - - g.restoreState(); } else if (clipBounds.intersects (child.getBounds())) { - g.saveState(); + Graphics::ScopedSaveState ss (g); if (child.flags.dontClipGraphicsFlag) { @@ -1949,15 +1949,12 @@ void Component::paintComponentAndChildren (Graphics& g) if (nothingClipped || ! g.isClipEmpty()) child.paintWithinParentContext (g); } - - g.restoreState(); } } } - g.saveState(); + Graphics::ScopedSaveState ss (g); paintOverChildren (g); - g.restoreState(); } void Component::paintEntireComponent (Graphics& g, bool ignoreAlphaLevel) @@ -1989,10 +1986,10 @@ void Component::paintEntireComponent (Graphics& g, bool ignoreAlphaLevel) paintComponentAndChildren (g2); } - g.saveState(); + Graphics::ScopedSaveState ss (g); + g.addTransform (AffineTransform::scale (1.0f / scale)); effect->applyEffect (effectImage, g, scale, ignoreAlphaLevel ? 1.0f : getAlpha()); - g.restoreState(); } else if (componentTransparency > 0 && ! ignoreAlphaLevel) { diff --git a/modules/juce_gui_basics/components/juce_Component.h b/modules/juce_gui_basics/components/juce_Component.h index 7dc3ed03..72d82cf0 100644 --- a/modules/juce_gui_basics/components/juce_Component.h +++ b/modules/juce_gui_basics/components/juce_Component.h @@ -54,7 +54,7 @@ public: /** Destructor. Note that when a component is deleted, any child components it contains are NOT - automatically deleted. It's your responsibilty to manage their lifespan - you + automatically deleted. It's your responsibility to manage their lifespan - you may want to use helper methods like deleteAllChildren(), or less haphazard approaches like using std::unique_ptrs or normal object aggregation to manage them. @@ -364,7 +364,7 @@ public: a screen coordinate. If you've used setTransform() to apply one or more transforms to components, then the source rectangle - may not actually be rectanglular when converted to the target space, so in that situation this will return + may not actually be rectangular when converted to the target space, so in that situation this will return the smallest rectangle that fully contains the transformed area. */ Rectangle getLocalArea (const Component* sourceComponent, @@ -383,7 +383,7 @@ public: /** Converts a rectangle from this component's coordinate space to a screen coordinate. If you've used setTransform() to apply one or more transforms to components, then the source rectangle - may not actually be rectanglular when converted to the target space, so in that situation this will return + may not actually be rectangular when converted to the target space, so in that situation this will return the smallest rectangle that fully contains the transformed area. @see getLocalPoint, localPointToGlobal */ @@ -1384,7 +1384,7 @@ public: virtual void enablementChanged(); //============================================================================== - /** Returns the component's current transparancy level. + /** Returns the component's current transparency level. See setAlpha() for more details. */ float getAlpha() const noexcept; diff --git a/modules/juce_gui_basics/drawables/juce_Drawable.h b/modules/juce_gui_basics/drawables/juce_Drawable.h index e743b2de..56ac7dfb 100644 --- a/modules/juce_gui_basics/drawables/juce_Drawable.h +++ b/modules/juce_gui_basics/drawables/juce_Drawable.h @@ -123,7 +123,7 @@ public: DrawableComposite* getParent() const; /** Sets a the clipping region of this drawable using another drawable. - The drawbale passed in will be deleted when no longer needed. + The drawable passed in will be deleted when no longer needed. */ void setClipPath (std::unique_ptr drawableClipPath); @@ -178,7 +178,7 @@ public: static Path parseSVGPath (const String& svgPath); //============================================================================== - /** Returns the area that this drawble covers. + /** Returns the area that this drawable covers. The result is expressed in this drawable's own coordinate space, and does not take into account any transforms that may be applied to the component. */ diff --git a/modules/juce_gui_basics/drawables/juce_SVGParser.cpp b/modules/juce_gui_basics/drawables/juce_SVGParser.cpp index 4f3b7ea5..d425a893 100644 --- a/modules/juce_gui_basics/drawables/juce_SVGParser.cpp +++ b/modules/juce_gui_basics/drawables/juce_SVGParser.cpp @@ -365,18 +365,19 @@ public: if (parseCoordsOrSkip (d, p1, false)) { String num; + bool flagValue = false; if (parseNextNumber (d, num, false)) { - const float angle = degreesToRadians (num.getFloatValue()); + auto angle = degreesToRadians (num.getFloatValue()); - if (parseNextNumber (d, num, false)) + if (parseNextFlag (d, flagValue)) { - const bool largeArc = num.getIntValue() != 0; + auto largeArc = flagValue; - if (parseNextNumber (d, num, false)) + if (parseNextFlag (d, flagValue)) { - const bool sweep = num.getIntValue() != 0; + auto sweep = flagValue; if (parseCoordsOrSkip (d, p2, false)) { @@ -1064,7 +1065,7 @@ private: if (xml->hasTagName ("use")) return useText (xml); - if (! xml->hasTagName ("text")) + if (! xml->hasTagName ("text") && ! xml->hasTagNameIgnoringNamespace ("tspan")) return nullptr; Array xCoords, yCoords, dxCoords, dyCoords; @@ -1501,6 +1502,22 @@ private: return true; } + static bool parseNextFlag (String::CharPointerType& text, bool& value) + { + while (text.isWhitespace() || *text == ',') + ++text; + + if (*text != '0' && *text != '1') + return false; + + value = *(text++) != '0'; + + while (text.isWhitespace() || *text == ',') + ++text; + + return true; + } + //============================================================================== Colour parseColour (const XmlPath& xml, StringRef attributeName, const Colour defaultColour) const { diff --git a/modules/juce_gui_basics/filebrowser/juce_FileChooser.h b/modules/juce_gui_basics/filebrowser/juce_FileChooser.h index 1398f33c..c834593f 100644 --- a/modules/juce_gui_basics/filebrowser/juce_FileChooser.h +++ b/modules/juce_gui_basics/filebrowser/juce_FileChooser.h @@ -222,7 +222,7 @@ public: if the user pressed 'ok' rather than cancelling). On mobile platforms, the file browser may return a URL instead of a local file. - Therefore, om mobile platforms, you should call getURLResult() instead. + Therefore, on mobile platforms, you should call getURLResult() instead. If you're using a multiple-file select, then use the getResults() method instead, to obtain the list of all files chosen. @@ -235,7 +235,7 @@ public: browse method. On mobile platforms, the file browser may return a URL instead of a local file. - Therefore, om mobile platforms, you should call getURLResults() instead. + Therefore, on mobile platforms, you should call getURLResults() instead. This array may be empty if no files were chosen, or can contain multiple entries if multiple files were chosen. @@ -293,7 +293,7 @@ public: Note: On iOS this will only return true if you have iCloud permissions and code-signing enabled in the Projucer and have added iCloud containers to your app in Apple's online developer portal. Additionally, the user must - have installed the iCloud app on their device and used the app at leat once. + have installed the iCloud app on their device and used the app at least once. */ static bool isPlatformDialogAvailable(); diff --git a/modules/juce_gui_basics/filebrowser/juce_FilePreviewComponent.h b/modules/juce_gui_basics/filebrowser/juce_FilePreviewComponent.h index 1e25368d..d5263daf 100644 --- a/modules/juce_gui_basics/filebrowser/juce_FilePreviewComponent.h +++ b/modules/juce_gui_basics/filebrowser/juce_FilePreviewComponent.h @@ -54,7 +54,7 @@ public: /** Called to indicate that the user's currently selected file has changed. @param newSelectedFile the newly selected file or directory, which may be - a defualt File() object if none is selected. + a default File() object if none is selected. */ virtual void selectedFileChanged (const File& newSelectedFile) = 0; diff --git a/modules/juce_gui_basics/juce_gui_basics.h b/modules/juce_gui_basics/juce_gui_basics.h index e6c0b74a..304cf049 100644 --- a/modules/juce_gui_basics/juce_gui_basics.h +++ b/modules/juce_gui_basics/juce_gui_basics.h @@ -24,6 +24,7 @@ ============================================================================== */ + /******************************************************************************* The block below describes the properties of this module, and is read by the Projucer to automatically generate project code that uses it. @@ -33,18 +34,18 @@ BEGIN_JUCE_MODULE_DECLARATION - ID: juce_gui_basics - vendor: juce - version: 5.4.5 - name: JUCE GUI core classes - description: Basic user-interface components and related classes. - website: http://www.juce.com/juce - license: GPL/Commercial + ID: juce_gui_basics + vendor: juce + version: 5.4.6 + name: JUCE GUI core classes + description: Basic user-interface components and related classes. + website: http://www.juce.com/juce + license: GPL/Commercial - dependencies: juce_graphics juce_data_structures - OSXFrameworks: Cocoa Carbon QuartzCore - iOSFrameworks: UIKit MobileCoreServices - linuxPackages: x11 xinerama xext + dependencies: juce_graphics juce_data_structures + OSXFrameworks: Cocoa Carbon QuartzCore + iOSFrameworks: UIKit MobileCoreServices + linuxPackages: x11 xinerama xext END_JUCE_MODULE_DECLARATION diff --git a/modules/juce_gui_basics/keyboard/juce_KeyPress.cpp b/modules/juce_gui_basics/keyboard/juce_KeyPress.cpp index ae1707d8..e5f8a0f6 100644 --- a/modules/juce_gui_basics/keyboard/juce_KeyPress.cpp +++ b/modules/juce_gui_basics/keyboard/juce_KeyPress.cpp @@ -146,7 +146,7 @@ namespace KeyPressHelpers return 0; } - #if JUCE_MAC + #if JUCE_MAC || JUCE_IOS struct OSXSymbolReplacement { const char* text; @@ -241,7 +241,7 @@ String KeyPress::getTextDescription() const if (mods.isCtrlDown()) desc << "ctrl + "; if (mods.isShiftDown()) desc << "shift + "; - #if JUCE_MAC + #if JUCE_MAC || JUCE_IOS if (mods.isAltDown()) desc << "option + "; if (mods.isCommandDown()) desc << "command + "; #else @@ -274,7 +274,7 @@ String KeyPress::getTextDescription() const String KeyPress::getTextDescriptionWithIcons() const { - #if JUCE_MAC + #if JUCE_MAC || JUCE_IOS auto s = getTextDescription(); for (int i = 0; i < numElementsInArray (KeyPressHelpers::osxSymbols); ++i) diff --git a/modules/juce_gui_basics/keyboard/juce_KeyPress.h b/modules/juce_gui_basics/keyboard/juce_KeyPress.h index 387c8d83..d9ed4266 100644 --- a/modules/juce_gui_basics/keyboard/juce_KeyPress.h +++ b/modules/juce_gui_basics/keyboard/juce_KeyPress.h @@ -53,8 +53,8 @@ public: /** Creates a KeyPress for a key and some modifiers. e.g. - CTRL+C would be: KeyPress ('c', ModifierKeys::ctrlModifier) - SHIFT+Escape would be: KeyPress (KeyPress::escapeKey, ModifierKeys::shiftModifier) + CTRL+C would be: KeyPress ('c', ModifierKeys::ctrlModifier, 0) + SHIFT+Escape would be: KeyPress (KeyPress::escapeKey, ModifierKeys::shiftModifier, 0) @param keyCode a code that represents the key - this value must be one of special constants listed in this class, or an diff --git a/modules/juce_gui_basics/keyboard/juce_ModifierKeys.h b/modules/juce_gui_basics/keyboard/juce_ModifierKeys.h index ed0fff22..ba8c813a 100644 --- a/modules/juce_gui_basics/keyboard/juce_ModifierKeys.h +++ b/modules/juce_gui_basics/keyboard/juce_ModifierKeys.h @@ -63,7 +63,7 @@ public: /** Checks whether the 'command' key flag is set (or 'ctrl' on Windows/Linux). This is a platform-agnostic way of checking for the operating system's - preferred command-key modifier - so on the Mac it tests for the Apple key, on + preferred command-key modifier - so on the Mac it tests for the cmd key, on Windows/Linux, it's actually checking for the CTRL key. */ inline bool isCommandDown() const noexcept { return testFlags (commandModifier); } @@ -136,7 +136,7 @@ public: /** Middle mouse button flag. */ middleButtonModifier = 64, - #if JUCE_MAC + #if JUCE_MAC || JUCE_IOS /** Command key flag - on windows this is the same as the CTRL key flag. */ commandModifier = 8, diff --git a/modules/juce_gui_basics/layout/juce_ComponentAnimator.cpp b/modules/juce_gui_basics/layout/juce_ComponentAnimator.cpp index bc58337c..9306a1c8 100644 --- a/modules/juce_gui_basics/layout/juce_ComponentAnimator.cpp +++ b/modules/juce_gui_basics/layout/juce_ComponentAnimator.cpp @@ -32,6 +32,11 @@ class ComponentAnimator::AnimationTask public: AnimationTask (Component* c) noexcept : component (c) {} + ~AnimationTask() + { + proxy.deleteAndZero(); + } + void reset (const Rectangle& finalBounds, float finalAlpha, int millisecondsToSpendMoving, @@ -58,17 +63,17 @@ public: midSpeed = invTotalDistance; endSpeed = jmax (0.0, endSpd * invTotalDistance); + proxy.deleteAndZero(); + if (useProxyComponent) - proxy.reset (new ProxyComponent (*component)); - else - proxy.reset(); + proxy = new ProxyComponent (*component); component->setVisible (! useProxyComponent); } bool useTimeslice (const int elapsed) { - if (auto* c = proxy != nullptr ? proxy.get() + if (auto* c = proxy != nullptr ? proxy.getComponent() : component.get()) { msElapsed += elapsed; @@ -159,7 +164,8 @@ public: else jassertfalse; // seem to be trying to animate a component that's not visible.. - auto scale = (float) Desktop::getInstance().getDisplays().findDisplayForRect (getScreenBounds()).scale; + auto scale = (float) Desktop::getInstance().getDisplays().findDisplayForRect (getScreenBounds()).scale + * Component::getApproximateScaleFactorForComponent (&c); image = c.createComponentSnapshot (c.getLocalBounds(), false, scale); @@ -181,7 +187,7 @@ public: }; WeakReference component; - std::unique_ptr proxy; + Component::SafePointer proxy; Rectangle destination; double destAlpha; diff --git a/modules/juce_gui_basics/layout/juce_ConcertinaPanel.cpp b/modules/juce_gui_basics/layout/juce_ConcertinaPanel.cpp index 685c79fe..30ca8151 100644 --- a/modules/juce_gui_basics/layout/juce_ConcertinaPanel.cpp +++ b/modules/juce_gui_basics/layout/juce_ConcertinaPanel.cpp @@ -255,10 +255,13 @@ public: void mouseDrag (const MouseEvent& e) override { - ConcertinaPanel& panel = getPanel(); - panel.setLayout (dragStartSizes.withMovedPanel (panel.holders.indexOf (this), - mouseDownY + e.getDistanceFromDragStartY(), - panel.getHeight()), false); + if (e.mouseWasDraggedSinceMouseDown()) + { + auto& panel = getPanel(); + panel.setLayout (dragStartSizes.withMovedPanel (panel.holders.indexOf (this), + mouseDownY + e.getDistanceFromDragStartY(), + panel.getHeight()), false); + } } void mouseDoubleClick (const MouseEvent&) override diff --git a/modules/juce_gui_basics/layout/juce_SidePanel.cpp b/modules/juce_gui_basics/layout/juce_SidePanel.cpp index e674a52d..04a10dbb 100644 --- a/modules/juce_gui_basics/layout/juce_SidePanel.cpp +++ b/modules/juce_gui_basics/layout/juce_SidePanel.cpp @@ -245,7 +245,7 @@ void SidePanel::componentMovedOrResized (Component& component, bool wasMoved, bo Rectangle SidePanel::calculateBoundsInParent (Component& parentComp) const { - auto parentBounds = parentComp.getBounds(); + auto parentBounds = parentComp.getLocalBounds(); if (isOnLeft) { diff --git a/modules/juce_gui_basics/layout/juce_Viewport.cpp b/modules/juce_gui_basics/layout/juce_Viewport.cpp index d10006cb..5dd8c252 100644 --- a/modules/juce_gui_basics/layout/juce_Viewport.cpp +++ b/modules/juce_gui_basics/layout/juce_Viewport.cpp @@ -389,7 +389,7 @@ void Viewport::updateVisibleArea() auto oldContentBounds = contentComp->getBounds(); contentHolder.setBounds (contentArea); - // If the content has changed its size, that might affect our scrollbars, so go round again and re-caclulate.. + // If the content has changed its size, that might affect our scrollbars, so go round again and re-calculate.. if (oldContentBounds == contentComp->getBounds()) break; } @@ -408,7 +408,6 @@ void Viewport::updateVisibleArea() hbar.setRangeLimits (0.0, contentBounds.getWidth()); hbar.setCurrentRange (visibleOrigin.x, contentArea.getWidth()); hbar.setSingleStepSize (singleStepX); - hbar.cancelPendingUpdate(); if (canShowHBar && ! hBarVisible) visibleOrigin.setX (0); @@ -417,7 +416,6 @@ void Viewport::updateVisibleArea() vbar.setRangeLimits (0.0, contentBounds.getHeight()); vbar.setCurrentRange (visibleOrigin.y, contentArea.getHeight()); vbar.setSingleStepSize (singleStepY); - vbar.cancelPendingUpdate(); if (canShowVBar && ! vBarVisible) visibleOrigin.setY (0); diff --git a/modules/juce_gui_basics/lookandfeel/juce_LookAndFeel.cpp b/modules/juce_gui_basics/lookandfeel/juce_LookAndFeel.cpp index d7579017..553bbe02 100644 --- a/modules/juce_gui_basics/lookandfeel/juce_LookAndFeel.cpp +++ b/modules/juce_gui_basics/lookandfeel/juce_LookAndFeel.cpp @@ -41,7 +41,7 @@ LookAndFeel::LookAndFeel() /* if this fails it means you're trying to create a LookAndFeel object before the static Colours have been initialised. That ain't gonna work. It probably means that you're using a static LookAndFeel object and that your compiler has - decided to intialise it before the Colours class. + decided to initialise it before the Colours class. */ jassert (Colours::white == Colour (0xffffffff)); diff --git a/modules/juce_gui_basics/lookandfeel/juce_LookAndFeel_V2.cpp b/modules/juce_gui_basics/lookandfeel/juce_LookAndFeel_V2.cpp index f1471200..1818f73f 100644 --- a/modules/juce_gui_basics/lookandfeel/juce_LookAndFeel_V2.cpp +++ b/modules/juce_gui_basics/lookandfeel/juce_LookAndFeel_V2.cpp @@ -774,15 +774,16 @@ void LookAndFeel_V2::drawScrollbar (Graphics& g, g.setGradientFill (ColourGradient (Colour (0x10000000), gx1, gy1, Colours::transparentBlack, gx2, gy2, false)); - g.saveState(); + { + Graphics::ScopedSaveState ss (g); - if (isScrollbarVertical) - g.reduceClipRegion (x + width / 2, y, width, height); - else - g.reduceClipRegion (x, y + height / 2, width, height); + if (isScrollbarVertical) + g.reduceClipRegion (x + width / 2, y, width, height); + else + g.reduceClipRegion (x, y + height / 2, width, height); - g.fillPath (thumbPath); - g.restoreState(); + g.fillPath (thumbPath); + } g.setColour (Colour (0x4c000000)); g.strokePath (thumbPath, PathStrokeType (0.4f)); @@ -1735,7 +1736,8 @@ void LookAndFeel_V2::drawResizableFrame (Graphics& g, int w, int h, const Border const Rectangle fullSize (0, 0, w, h); auto centreArea = border.subtractedFrom (fullSize); - g.saveState(); + Graphics::ScopedSaveState ss (g); + g.excludeClipRegion (centreArea); g.setColour (Colour (0x50000000)); @@ -1743,8 +1745,6 @@ void LookAndFeel_V2::drawResizableFrame (Graphics& g, int w, int h, const Border g.setColour (Colour (0x19000000)); g.drawRect (centreArea.expanded (1, 1)); - - g.restoreState(); } } @@ -2834,7 +2834,7 @@ void LookAndFeel_V2::drawBevel (Graphics& g, const int x, const int y, const int if (g.clipRegionIntersects (Rectangle (x, y, width, height))) { auto& context = g.getInternalContext(); - context.saveState(); + Graphics::ScopedSaveState ss (g); for (int i = bevelThickness; --i >= 0;) { @@ -2850,8 +2850,6 @@ void LookAndFeel_V2::drawBevel (Graphics& g, const int x, const int y, const int context.setFill (bottomRightColour.withMultipliedAlpha (op * 0.75f)); context.fillRect (Rectangle (x + width - i - 1, y + i + 1, 1, height - i * 2 - 2), false); } - - context.restoreState(); } } @@ -3015,11 +3013,11 @@ void LookAndFeel_V2::drawGlassLozenge (Graphics& g, if (! (flatOnLeft || flatOnTop || flatOnBottom)) { - g.saveState(); + Graphics::ScopedSaveState ss (g); + g.setGradientFill (cg); g.reduceClipRegion (intX, intY, intEdge, intH); g.fillPath (outline); - g.restoreState(); } if (! (flatOnRight || flatOnTop || flatOnBottom)) @@ -3027,11 +3025,11 @@ void LookAndFeel_V2::drawGlassLozenge (Graphics& g, cg.point1.setX (x + width - edgeBlurRadius); cg.point2.setX (x + width); - g.saveState(); + Graphics::ScopedSaveState ss (g); + g.setGradientFill (cg); g.reduceClipRegion (intX + intW - intEdge, intY, 2 + intEdge, intH); g.fillPath (outline); - g.restoreState(); } { diff --git a/modules/juce_gui_basics/menus/juce_PopupMenu.cpp b/modules/juce_gui_basics/menus/juce_PopupMenu.cpp index cbd79a66..3e273179 100644 --- a/modules/juce_gui_basics/menus/juce_PopupMenu.cpp +++ b/modules/juce_gui_basics/menus/juce_PopupMenu.cpp @@ -55,10 +55,7 @@ struct HeaderItemComponent : public PopupMenu::CustomComponent setName (name); } - void paint (Graphics& g) override - { - getLookAndFeel().drawPopupMenuSectionHeader (g, getLocalBounds(), getName()); - } + void paint (Graphics& g) override; void getIdealSize (int& idealWidth, int& idealHeight) override { @@ -97,13 +94,7 @@ struct ItemComponent : public Component addMouseListener (&parent, false); } - ~ItemComponent() override - { - if (customComp != nullptr) - setItem (*customComp, nullptr); - - removeChildComponent (customComp.get()); - } + ~ItemComponent() override; void getIdealSize (int& idealWidth, int& idealHeight, const int standardItemHeight) { @@ -273,13 +264,7 @@ struct MenuWindow : public Component getMouseState (Desktop::getInstance().getMainMouseSource()); // forces creation of a mouse source watcher for the main mouse } - ~MenuWindow() override - { - getActiveWindows().removeFirstMatchingValue (this); - Desktop::getInstance().removeGlobalMouseListener (this); - activeSubMenu.reset(); - items.clear(); - } + ~MenuWindow() override; //============================================================================== void paint (Graphics& g) override @@ -464,7 +449,7 @@ struct MenuWindow : public Component if (componentAttachedTo->reallyContains (mousePos, true)) { - postCommandMessage (PopupMenuSettings::dismissCommandId); // dismiss asynchrounously + postCommandMessage (PopupMenuSettings::dismissCommandId); // dismiss asynchronously return; } } @@ -610,7 +595,7 @@ struct MenuWindow : public Component if (relativeTo != nullptr) targetPoint = relativeTo->localPointToGlobal (targetPoint); - auto parentArea = Desktop::getInstance().getDisplays().findDisplayForPoint (targetPoint) + auto parentArea = Desktop::getInstance().getDisplays().findDisplayForPoint (targetPoint * scaleFactor) #if JUCE_MAC || JUCE_ANDROID .userArea; #else @@ -1013,14 +998,7 @@ public: startTimerHz (20); } - void handleMouseEvent (const MouseEvent& e) - { - if (! window.windowIsStillValid()) - return; - - startTimerHz (20); - handleMousePosition (e.getScreenPosition()); - } + void handleMouseEvent (const MouseEvent& e); void timerCallback() override { @@ -1250,11 +1228,7 @@ struct NormalComponentWrapper : public PopupMenu::CustomComponent addAndMakeVisible (comp); } - void getIdealSize (int& idealWidth, int& idealHeight) override - { - idealWidth = width; - idealHeight = height; - } + void getIdealSize (int& idealWidth, int& idealHeight) override; void resized() override { @@ -1269,6 +1243,44 @@ struct NormalComponentWrapper : public PopupMenu::CustomComponent }; +// The following implementations are outside of the class definitions to avoid spurious +// warning messages when dynamically loading libraries at runtime on macOS +void PopupMenu::HelperClasses::HeaderItemComponent::paint (Graphics& g) +{ + getLookAndFeel().drawPopupMenuSectionHeader (g, getLocalBounds(), getName()); +} + +PopupMenu::HelperClasses::ItemComponent::~ItemComponent() +{ + if (customComp != nullptr) + setItem (*customComp, nullptr); + + removeChildComponent (customComp.get()); +} + +PopupMenu::HelperClasses::MenuWindow::~MenuWindow() +{ + getActiveWindows().removeFirstMatchingValue (this); + Desktop::getInstance().removeGlobalMouseListener (this); + activeSubMenu.reset(); + items.clear(); +} + +void PopupMenu::HelperClasses::MouseSourceState::handleMouseEvent (const MouseEvent& e) +{ + if (! window.windowIsStillValid()) + return; + + startTimerHz (20); + handleMousePosition (e.getScreenPosition()); +} + +void PopupMenu::HelperClasses::NormalComponentWrapper::getIdealSize (int& idealWidth, int& idealHeight) +{ + idealWidth = width; + idealHeight = height; +} + //============================================================================== PopupMenu::PopupMenu() { @@ -1391,6 +1403,12 @@ PopupMenu::Item& PopupMenu::Item::setCustomComponent (ReferenceCountedObjectPtr< return *this; } +PopupMenu::Item& PopupMenu::Item::setImage (std::unique_ptr newImage) & noexcept +{ + image = std::move (newImage); + return *this; +} + PopupMenu::Item&& PopupMenu::Item::setTicked (bool shouldBeTicked) && noexcept { isTicked = shouldBeTicked; @@ -1427,6 +1445,12 @@ PopupMenu::Item&& PopupMenu::Item::setCustomComponent (ReferenceCountedObjectPtr return std::move (*this); } +PopupMenu::Item&& PopupMenu::Item::setImage (std::unique_ptr newImage) && noexcept +{ + image = std::move (newImage); + return std::move (*this); +} + void PopupMenu::addItem (Item newItem) { // An ID of 0 is used as a return value to indicate that the user diff --git a/modules/juce_gui_basics/menus/juce_PopupMenu.h b/modules/juce_gui_basics/menus/juce_PopupMenu.h index 95c6661f..60bedebf 100644 --- a/modules/juce_gui_basics/menus/juce_PopupMenu.h +++ b/modules/juce_gui_basics/menus/juce_PopupMenu.h @@ -192,6 +192,8 @@ public: Item& setColour (Colour) & noexcept; /** Sets the customComponent property (and returns a reference to this item to allow chaining). */ Item& setCustomComponent (ReferenceCountedObjectPtr customComponent) & noexcept; + /** Sets the image property (and returns a reference to this item to allow chaining). */ + Item& setImage (std::unique_ptr) & noexcept; /** Sets the isTicked flag (and returns a reference to this item to allow chaining). */ Item&& setTicked (bool shouldBeTicked = true) && noexcept; @@ -205,6 +207,8 @@ public: Item&& setColour (Colour) && noexcept; /** Sets the customComponent property (and returns a reference to this item to allow chaining). */ Item&& setCustomComponent (ReferenceCountedObjectPtr customComponent) && noexcept; + /** Sets the image property (and returns a reference to this item to allow chaining). */ + Item&& setImage (std::unique_ptr) && noexcept; }; /** Adds an item to the menu. @@ -395,7 +399,7 @@ public: /** Appends a separator to the menu, to help break it up into sections. The menu class is smart enough not to display separators at the top or bottom - of the menu, and it will replace mutliple adjacent separators with a single + of the menu, and it will replace multiple adjacent separators with a single one, so your code can be quite free and easy about adding these, and it'll always look ok. */ diff --git a/modules/juce_gui_basics/mouse/juce_ComponentDragger.h b/modules/juce_gui_basics/mouse/juce_ComponentDragger.h index eec0c5b2..f8e0cb22 100644 --- a/modules/juce_gui_basics/mouse/juce_ComponentDragger.h +++ b/modules/juce_gui_basics/mouse/juce_ComponentDragger.h @@ -85,7 +85,7 @@ public: @param e the current mouse-drag event @param constrainer an optional constrainer object that should be used to apply limits to the component's position. Pass - null if you don't want to contrain the movement. + null if you don't want to constrain the movement. @see startDraggingComponent */ void dragComponent (Component* componentToDrag, diff --git a/modules/juce_gui_basics/mouse/juce_DragAndDropContainer.cpp b/modules/juce_gui_basics/mouse/juce_DragAndDropContainer.cpp index 185dda53..cff272c0 100644 --- a/modules/juce_gui_basics/mouse/juce_DragAndDropContainer.cpp +++ b/modules/juce_gui_basics/mouse/juce_DragAndDropContainer.cpp @@ -482,6 +482,7 @@ void DragAndDropContainer::startDragging (const var& sourceDescription, } } + dragImageComponent->sourceDetails.localPosition = sourceComponent->getLocalPoint (nullptr, lastMouseDown); dragImageComponent->updateLocation (false, lastMouseDown); #if JUCE_WINDOWS diff --git a/modules/juce_gui_basics/mouse/juce_DragAndDropTarget.h b/modules/juce_gui_basics/mouse/juce_DragAndDropTarget.h index 92a3d0c8..8ba892c3 100644 --- a/modules/juce_gui_basics/mouse/juce_DragAndDropTarget.h +++ b/modules/juce_gui_basics/mouse/juce_DragAndDropTarget.h @@ -76,7 +76,7 @@ public: dragged. @param dragSourceDetails contains information about the source of the drag operation. - @returns true if this component wants to receive the other callbacks regarging this + @returns true if this component wants to receive the other callbacks regarding this type of object; if it returns false, no other callbacks will be made. */ virtual bool isInterestedInDragSource (const SourceDetails& dragSourceDetails) = 0; diff --git a/modules/juce_gui_basics/mouse/juce_FileDragAndDropTarget.h b/modules/juce_gui_basics/mouse/juce_FileDragAndDropTarget.h index 709e1f34..d3bc5597 100644 --- a/modules/juce_gui_basics/mouse/juce_FileDragAndDropTarget.h +++ b/modules/juce_gui_basics/mouse/juce_FileDragAndDropTarget.h @@ -47,7 +47,7 @@ public: inside them! @param files the set of (absolute) pathnames of the files that the user is dragging - @returns true if this component wants to receive the other callbacks regarging this + @returns true if this component wants to receive the other callbacks regarding this type of object; if it returns false, no other callbacks will be made. */ virtual bool isInterestedInFileDrag (const StringArray& files) = 0; diff --git a/modules/juce_gui_basics/mouse/juce_MouseCursor.h b/modules/juce_gui_basics/mouse/juce_MouseCursor.h index 2010699b..e64c75bc 100644 --- a/modules/juce_gui_basics/mouse/juce_MouseCursor.h +++ b/modules/juce_gui_basics/mouse/juce_MouseCursor.h @@ -46,7 +46,7 @@ public: ParentCursor = 0, /**< Indicates that the component's parent's cursor should be used. */ NoCursor, /**< An invisible cursor. */ - NormalCursor, /**< The stardard arrow cursor. */ + NormalCursor, /**< The standard arrow cursor. */ WaitCursor, /**< The normal hourglass or spinning-beachball 'busy' cursor. */ IBeamCursor, /**< A vertical I-beam for positioning within text. */ diff --git a/modules/juce_gui_basics/mouse/juce_MouseEvent.h b/modules/juce_gui_basics/mouse/juce_MouseEvent.h index d47a30c8..2af4a9c3 100644 --- a/modules/juce_gui_basics/mouse/juce_MouseEvent.h +++ b/modules/juce_gui_basics/mouse/juce_MouseEvent.h @@ -417,7 +417,7 @@ struct MouseWheelDetails final /** If true, then the wheel has continuous, un-stepped motion. */ bool isSmooth; - /** If true, then this event is part of the intertial momentum phase that follows + /** If true, then this event is part of the inertial momentum phase that follows the wheel being released. */ bool isInertial; }; diff --git a/modules/juce_gui_basics/mouse/juce_MouseInputSource.h b/modules/juce_gui_basics/mouse/juce_MouseInputSource.h index f10f3d00..5fd7b2ca 100644 --- a/modules/juce_gui_basics/mouse/juce_MouseInputSource.h +++ b/modules/juce_gui_basics/mouse/juce_MouseInputSource.h @@ -35,7 +35,7 @@ namespace juce Each MouseEvent object contains a reference to the MouseInputSource that generated it. In an environment with a single mouse for input, all events will come from the same source, but in a multi-touch system, there may be multiple MouseInputSource - obects active, each representing a stream of events coming from a particular finger. + objects active, each representing a stream of events coming from a particular finger. Events coming from a single MouseInputSource are always sent in a fixed and predictable order: a mouseMove will never be called without a mouseEnter having been sent beforehand, diff --git a/modules/juce_gui_basics/mouse/juce_TextDragAndDropTarget.h b/modules/juce_gui_basics/mouse/juce_TextDragAndDropTarget.h index 46d29388..b1ffd28d 100644 --- a/modules/juce_gui_basics/mouse/juce_TextDragAndDropTarget.h +++ b/modules/juce_gui_basics/mouse/juce_TextDragAndDropTarget.h @@ -47,7 +47,7 @@ public: component, so don't do anything time-consuming in here! @param text the text that the user is dragging - @returns true if this component wants to receive the other callbacks regarging this + @returns true if this component wants to receive the other callbacks regarding this type of object; if it returns false, no other callbacks will be made. */ virtual bool isInterestedInTextDrag (const String& text) = 0; diff --git a/modules/juce_gui_basics/native/juce_android_ContentSharer.cpp b/modules/juce_gui_basics/native/juce_android_ContentSharer.cpp index b985f3d4..6773956c 100644 --- a/modules/juce_gui_basics/native/juce_android_ContentSharer.cpp +++ b/modules/juce_gui_basics/native/juce_android_ContentSharer.cpp @@ -30,82 +30,57 @@ namespace juce // This byte-code is generated from native/javacore/app/com/roli/juce/JuceSharingContentProvider.java with min sdk version 16 // See juce_core/native/java/README.txt on how to generate this byte-code. static const uint8 javaJuceSharingContentProvider[] = -{100,101,120,10,48,51,53,0,66,68,79,209,68,153,2,8,5,37,136,73,129,38,235,114,135,129,180,66,79,170,89,247,100,13,0,0,112,0,0, -0,120,86,52,18,0,0,0,0,0,0,0,0,160,12,0,0,77,0,0,0,112,0,0,0,21,0,0,0,164,1,0,0,18,0,0,0,248,1,0,0,5,0,0,0,208,2,0,0,25,0,0,0, -248,2,0,0,3,0,0,0,192,3,0,0,68,9,0,0,32,4,0,0,226,6,0,0,234,6,0,0,237,6,0,0,243,6,0,0,250,6,0,0,253,6,0,0,30,7,0,0,33,7,0,0,37, -7,0,0,42,7,0,0,50,7,0,0,85,7,0,0,118,7,0,0,161,7,0,0,188,7,0,0,221,7,0,0,240,7,0,0,11,8,0,0,46,8,0,0,105,8,0,0,170,8,0,0,214, -8,0,0,250,8,0,0,26,9,0,0,61,9,0,0,81,9,0,0,101,9,0,0,117,9,0,0,139,9,0,0,142,9,0,0,147,9,0,0,151,9,0,0,157,9,0,0,161,9,0,0,166, -9,0,0,172,9,0,0,179,9,0,0,182,9,0,0,203,9,0,0,216,9,0,0,223,9,0,0,236,9,0,0,7,10,0,0,39,10,0,0,68,10,0,0,91,10,0,0,111,10,0, -0,119,10,0,0,126,10,0,0,151,10,0,0,167,10,0,0,176,10,0,0,182,10,0,0,193,10,0,0,201,10,0,0,207,10,0,0,213,10,0,0,229,10,0,0,235, -10,0,0,241,10,0,0,251,10,0,0,4,11,0,0,19,11,0,0,29,11,0,0,35,11,0,0,47,11,0,0,54,11,0,0,62,11,0,0,73,11,0,0,88,11,0,0,99,11, -0,0,105,11,0,0,113,11,0,0,121,11,0,0,126,11,0,0,131,11,0,0,138,11,0,0,1,0,0,0,4,0,0,0,10,0,0,0,11,0,0,0,12,0,0,0,13,0,0,0,14, -0,0,0,15,0,0,0,16,0,0,0,17,0,0,0,18,0,0,0,19,0,0,0,20,0,0,0,21,0,0,0,22,0,0,0,23,0,0,0,24,0,0,0,25,0,0,0,28,0,0,0,36,0,0,0,37, -0,0,0,3,0,0,0,0,0,0,0,96,6,0,0,2,0,0,0,0,0,0,0,108,6,0,0,8,0,0,0,4,0,0,0,120,6,0,0,9,0,0,0,5,0,0,0,128,6,0,0,8,0,0,0,7,0,0,0, -144,6,0,0,6,0,0,0,9,0,0,0,0,0,0,0,8,0,0,0,9,0,0,0,120,6,0,0,7,0,0,0,17,0,0,0,152,6,0,0,28,0,0,0,18,0,0,0,0,0,0,0,29,0,0,0,18, -0,0,0,160,6,0,0,30,0,0,0,18,0,0,0,168,6,0,0,31,0,0,0,18,0,0,0,176,6,0,0,35,0,0,0,18,0,0,0,188,6,0,0,34,0,0,0,18,0,0,0,200,6, -0,0,33,0,0,0,18,0,0,0,212,6,0,0,32,0,0,0,18,0,0,0,220,6,0,0,36,0,0,0,19,0,0,0,0,0,0,0,8,0,0,0,20,0,0,0,120,6,0,0,10,0,1,0,51,0, -0,0,10,0,12,0,71,0,0,0,11,0,1,0,51,0,0,0,11,0,12,0,71,0,0,0,12,0,16,0,54,0,0,0,2,0,8,0,0,0,0,0,4,0,5,0,48,0,0,0,6,0,15,0,0,0, -0,0,6,0,8,0,39,0,0,0,8,0,14,0,0,0,0,0,10,0,13,0,0,0,0,0,10,0,8,0,39,0,0,0,10,0,10,0,41,0,0,0,11,0,12,0,0,0,0,0,11,0,11,0,42,0, -0,0,11,0,9,0,60,0,0,0,12,0,8,0,0,0,0,0,12,0,17,0,43,0,0,0,12,0,2,0,44,0,0,0,12,0,3,0,45,0,0,0,12,0,1,0,46,0,0,0,12,0,17,0,49,0, -0,0,12,0,7,0,50,0,0,0,12,0,4,0,53,0,0,0,12,0,16,0,59,0,0,0,12,0,2,0,61,0,0,0,12,0,6,0,62,0,0,0,12,0,3,0,65,0,0,0,12,0,0,0,72, -0,0,0,16,0,8,0,0,0,0,0,10,0,0,0,17,0,0,0,6,0,0,0,0,0,0,0,5,0,0,0,48,6,0,0,52,12,0,0,0,0,0,0,11,0,0,0,17,0,0,0,8,0,0,0,0,0,0,0, -5,0,0,0,64,6,0,0,75,12,0,0,0,0,0,0,12,0,0,0,17,0,0,0,2,0,0,0,0,0,0,0,5,0,0,0,80,6,0,0,98,12,0,0,0,0,0,0,2,0,0,0,18,12,0,0,24, -12,0,0,2,0,0,0,18,12,0,0,33,12,0,0,1,0,0,0,42,12,0,0,5,0,5,0,2,0,0,0,146,11,0,0,8,0,0,0,91,1,1,0,112,32,2,0,64,0,90,2,0,0,14, -0,3,0,1,0,3,0,0,0,157,11,0,0,9,0,0,0,111,16,3,0,2,0,83,32,0,0,112,48,7,0,2,1,14,0,0,0,6,0,6,0,3,0,0,0,164,11,0,0,8,0,0,0,91,1, -3,0,112,48,4,0,64,5,90,2,2,0,14,0,5,0,3,0,5,0,0,0,176,11,0,0,6,0,0,0,83,32,2,0,112,84,9,0,2,49,14,0,2,0,1,0,1,0,0,0,184,11,0, -0,11,0,0,0,112,16,0,0,1,0,34,0,16,0,112,16,24,0,0,0,91,16,4,0,14,0,0,0,5,0,4,0,0,0,0,0,190,11,0,0,2,0,0,0,18,0,15,0,5,0,3,0,3, -0,1,0,198,11,0,0,12,0,0,0,84,33,4,0,29,1,112,48,12,0,50,4,12,0,30,1,17,0,13,0,30,1,39,0,3,0,0,0,8,0,1,0,1,0,9,0,3,0,2,0,0,0,0, -0,208,11,0,0,2,0,0,0,18,0,17,0,4,0,3,0,0,0,0,0,214,11,0,0,2,0,0,0,18,0,17,0,2,0,1,0,0,0,0,0,221,11,0,0,2,0,0,0,18,16,15,0,5, -0,3,0,3,0,1,0,226,11,0,0,12,0,0,0,84,33,4,0,29,1,112,48,13,0,50,4,12,0,30,1,17,0,13,0,30,1,39,0,3,0,0,0,8,0,1,0,1,0,9,0,6,0,3, -0,3,0,1,0,235,11,0,0,21,0,0,0,84,50,4,0,29,2,112,48,13,0,67,5,12,0,56,0,8,0,110,16,1,0,0,0,12,1,30,2,17,1,18,1,30,2,40,253,13, -1,30,2,39,1,0,0,3,0,0,0,17,0,1,0,1,0,18,0,8,0,6,0,6,0,1,0,253,11,0,0,12,0,0,0,84,33,4,0,29,1,118,6,14,0,2,0,12,0,30,1,17,0,13, -0,30,1,39,0,3,0,0,0,8,0,1,0,1,0,9,0,6,0,5,0,0,0,0,0,9,12,0,0,2,0,0,0,18,0,15,0,32,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,44,4,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,56,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,7,0,3,0,17,0,20,0,3,0,0,0,7,0,17,0,20,0,0,0,2,0,0,0,7,0,17,0,5,0, -0,0,7,0,20,0,17,0,20,0,17,0,0,0,2,0,0,0,7,0,3,0,1,0,0,0,7,0,0,0,2,0,0,0,0,0,17,0,1,0,0,0,1,0,0,0,3,0,0,0,1,0,0,0,17,0,0,0,4, -0,0,0,12,0,1,0,17,0,0,0,3,0,0,0,12,0,1,0,20,0,0,0,2,0,0,0,17,0,0,0,1,0,0,0,20,0,6,60,105,110,105,116,62,0,1,73,0,4,73,76,76,76, -0,5,73,76,76,76,76,0,1,74,0,31,74,117,99,101,83,104,97,114,105,110,103,67,111,110,116,101,110,116,80,114,111,118,105,100,101, -114,46,106,97,118,97,0,1,76,0,2,76,76,0,3,76,76,76,0,6,76,76,76,76,76,76,0,33,76,97,110,100,114,111,105,100,47,99,111,110,116, -101,110,116,47,67,111,110,116,101,110,116,80,114,111,118,105,100,101,114,59,0,31,76,97,110,100,114,111,105,100,47,99,111,110, -116,101,110,116,47,67,111,110,116,101,110,116,86,97,108,117,101,115,59,0,41,76,97,110,100,114,111,105,100,47,99,111,110,116, -101,110,116,47,114,101,115,47,65,115,115,101,116,70,105,108,101,68,101,115,99,114,105,112,116,111,114,59,0,25,76,97,110,100,114, -111,105,100,47,100,97,116,97,98,97,115,101,47,67,117,114,115,111,114,59,0,31,76,97,110,100,114,111,105,100,47,100,97,116,97,98, -97,115,101,47,77,97,116,114,105,120,67,117,114,115,111,114,59,0,17,76,97,110,100,114,111,105,100,47,110,101,116,47,85,114,105, -59,0,25,76,97,110,100,114,111,105,100,47,111,115,47,70,105,108,101,79,98,115,101,114,118,101,114,59,0,33,76,97,110,100,114,111, -105,100,47,111,115,47,80,97,114,99,101,108,70,105,108,101,68,101,115,99,114,105,112,116,111,114,59,0,57,76,99,111,109,47,114, -111,108,105,47,106,117,99,101,47,74,117,99,101,83,104,97,114,105,110,103,67,111,110,116,101,110,116,80,114,111,118,105,100,101, -114,36,80,114,111,118,105,100,101,114,67,117,114,115,111,114,59,0,63,76,99,111,109,47,114,111,108,105,47,106,117,99,101,47, -74,117,99,101,83,104,97,114,105,110,103,67,111,110,116,101,110,116,80,114,111,118,105,100,101,114,36,80,114,111,118,105,100,101, -114,70,105,108,101,79,98,115,101,114,118,101,114,59,0,42,76,99,111,109,47,114,111,108,105,47,106,117,99,101,47,74,117,99,101, -83,104,97,114,105,110,103,67,111,110,116,101,110,116,80,114,111,118,105,100,101,114,59,0,34,76,100,97,108,118,105,107,47,97, -110,110,111,116,97,116,105,111,110,47,69,110,99,108,111,115,105,110,103,67,108,97,115,115,59,0,30,76,100,97,108,118,105,107,47, -97,110,110,111,116,97,116,105,111,110,47,73,110,110,101,114,67,108,97,115,115,59,0,33,76,100,97,108,118,105,107,47,97,110,110, -111,116,97,116,105,111,110,47,77,101,109,98,101,114,67,108,97,115,115,101,115,59,0,18,76,106,97,118,97,47,108,97,110,103,47, -79,98,106,101,99,116,59,0,18,76,106,97,118,97,47,108,97,110,103,47,83,116,114,105,110,103,59,0,14,80,114,111,118,105,100,101, -114,67,117,114,115,111,114,0,20,80,114,111,118,105,100,101,114,70,105,108,101,79,98,115,101,114,118,101,114,0,1,86,0,3,86,73, -76,0,2,86,74,0,4,86,74,73,76,0,2,86,76,0,3,86,76,73,0,4,86,76,74,76,0,5,86,76,74,76,73,0,1,90,0,19,91,76,106,97,118,97,47,108, -97,110,103,47,83,116,114,105,110,103,59,0,11,97,99,99,101,115,115,70,108,97,103,115,0,5,99,108,111,115,101,0,11,99,111,108,117, -109,110,78,97,109,101,115,0,25,99,111,110,116,101,110,116,83,104,97,114,101,114,67,117,114,115,111,114,67,108,111,115,101,100, -0,30,99,111,110,116,101,110,116,83,104,97,114,101,114,70,105,108,101,79,98,115,101,114,118,101,114,69,118,101,110,116,0,27,99, -111,110,116,101,110,116,83,104,97,114,101,114,71,101,116,83,116,114,101,97,109,84,121,112,101,115,0,21,99,111,110,116,101,110, -116,83,104,97,114,101,114,79,112,101,110,70,105,108,101,0,18,99,111,110,116,101,110,116,83,104,97,114,101,114,81,117,101,114, -121,0,6,100,101,108,101,116,101,0,5,101,118,101,110,116,0,23,103,101,116,80,97,114,99,101,108,70,105,108,101,68,101,115,99,114, -105,112,116,111,114,0,14,103,101,116,83,116,114,101,97,109,84,121,112,101,115,0,7,103,101,116,84,121,112,101,0,4,104,111,115, -116,0,9,104,111,115,116,84,111,85,115,101,0,6,105,110,115,101,114,116,0,4,108,111,99,107,0,4,109,97,115,107,0,14,109,105,109, -101,84,121,112,101,70,105,108,116,101,114,0,4,109,111,100,101,0,4,110,97,109,101,0,8,111,110,67,114,101,97,116,101,0,7,111,110, -69,118,101,110,116,0,13,111,112,101,110,65,115,115,101,116,70,105,108,101,0,8,111,112,101,110,70,105,108,101,0,4,112,97,116, -104,0,10,112,114,111,106,101,99,116,105,111,110,0,5,113,117,101,114,121,0,6,114,101,115,117,108,116,0,9,115,101,108,101,99,116, -105,111,110,0,13,115,101,108,101,99,116,105,111,110,65,114,103,115,0,9,115,111,114,116,79,114,100,101,114,0,4,116,104,105,115, -0,6,116,104,105,115,36,48,0,6,117,112,100,97,116,101,0,3,117,114,105,0,3,117,114,108,0,5,118,97,108,117,101,0,6,118,97,108,117, -101,115,0,46,3,72,53,41,7,14,45,61,45,0,55,0,7,14,61,90,0,27,4,72,53,64,56,7,14,45,61,45,0,35,2,48,64,7,14,90,0,15,0,7,14,61,0, -97,3,74,68,69,7,14,0,131,1,2,74,57,7,14,61,105,0,103,1,74,7,14,0,84,2,74,77,7,14,0,68,0,7,14,0,109,2,74,58,7,14,61,105,0,118, -2,74,58,7,14,61,76,3,0,67,5,45,91,75,5,0,0,75,5,75,65,68,69,70,7,14,61,105,0,91,4,74,77,68,69,7,14,0,2,13,1,75,24,12,2,14,2,38, -4,17,58,23,26,2,14,2,38,4,17,58,23,27,2,15,1,75,28,2,24,10,24,11,0,2,2,1,0,2,1,144,32,5,128,128,4,192,8,2,130,2,0,6,1,224,8, -0,2,2,1,2,2,1,144,32,8,129,128,4,132,9,1,130,2,0,10,1,164,9,0,1,4,9,4,2,11,129,128,4,192,9,1,130,2,0,1,130,2,0,1,130,2,0,15,1, -232,9,1,1,252,9,1,1,176,10,1,1,196,10,1,1,216,10,1,1,236,10,1,1,160,11,1,1,232,11,1,1,156,12,0,0,16,0,0,0,0,0,0,0,1,0,0,0,0, -0,0,0,1,0,0,0,77,0,0,0,112,0,0,0,2,0,0,0,21,0,0,0,164,1,0,0,3,0,0,0,18,0,0,0,248,1,0,0,4,0,0,0,5,0,0,0,208,2,0,0,5,0,0,0,25,0, -0,0,248,2,0,0,6,0,0,0,3,0,0,0,192,3,0,0,3,16,0,0,3,0,0,0,32,4,0,0,1,32,0,0,14,0,0,0,64,4,0,0,6,32,0,0,3,0,0,0,48,6,0,0,1,16, -0,0,13,0,0,0,96,6,0,0,2,32,0,0,77,0,0,0,226,6,0,0,3,32,0,0,14,0,0,0,146,11,0,0,4,32,0,0,4,0,0,0,18,12,0,0,0,32,0,0,3,0,0,0,52, -12,0,0,0,16,0,0,1,0,0,0,160,12,0,0,0,0}; +{31,139,8,8,96,160,247,93,0,3,74,97,118,97,68,101,120,66,121,116,101,67,111,100,101,46,100,101,120,0,149,151,93,108,20,85,20, +199,207,157,153,157,253,236,178,91,170,20,145,178,229,83,80,216,242,165,96,5,11,45,72,183,91,139,161,52,218,190,56,221,157,148, +129,221,153,101,102,118,133,23,2,106,162,209,196,24,125,64,19,73,48,33,106,140,15,36,26,227,131,49,152,24,163,241,65,77,148,248, +160,209,152,152,24,193,68,227,131,6,37,241,127,63,118,219,173,197,232,194,111,238,185,231,156,123,238,185,231,222,153,206, +148,237,19,137,190,173,219,105,239,208,216,231,67,47,106,177,200,154,39,135,207,172,189,226,63,113,230,173,189,99,175,63,244, +123,185,131,168,70,68,39,38,182,117,146,250,157,79,17,141,146,212,223,4,46,48,34,110,252,3,109,4,237,103,26,209,82,222,71,171, +163,189,132,203,80,156,40,103,16,125,111,18,253,4,126,6,191,129,107,224,58,232,137,18,245,130,53,96,3,216,2,14,131,6,120,25,188, +11,190,1,191,128,100,140,104,19,112,192,235,224,50,184,6,110,193,28,187,192,3,192,6,117,240,52,120,6,60,15,206,130,115,224, +101,240,10,120,3,188,9,222,6,159,128,175,192,183,224,42,136,38,136,214,129,33,48,5,60,240,8,56,5,206,130,87,193,69,240,54,120, +31,124,12,62,5,95,130,31,192,21,240,43,248,19,24,73,162,197,96,57,88,5,242,224,78,176,27,12,131,7,65,9,56,224,56,56,9,78,129, +199,192,83,0,101,37,148,142,16,138,208,37,148,159,176,45,148,6,139,64,6,100,73,238,193,98,208,165,246,229,102,176,4,116,147, +220,143,91,193,106,176,134,228,190,240,223,195,168,189,166,228,10,228,152,154,235,4,100,148,65,236,231,105,165,71,233,233,89,200, +248,47,108,252,23,83,50,247,143,170,60,94,48,229,92,205,3,179,92,201,231,249,62,43,249,53,200,43,148,124,17,242,42,37,191,11, +121,165,146,63,130,220,171,228,47,32,231,148,252,181,41,215,177,120,78,14,93,42,135,4,170,181,85,212,42,69,247,137,122,201,126, +82,245,83,168,214,157,196,215,28,19,99,13,172,176,143,248,154,22,137,190,9,253,58,17,51,45,250,9,81,105,222,74,125,2,255,214, +171,120,36,218,36,109,16,109,156,238,17,241,101,220,20,42,113,187,104,53,186,67,180,58,109,20,45,163,77,202,190,89,180,81,218, +34,90,131,182,171,252,250,213,184,93,162,53,105,183,26,191,71,237,253,1,177,231,49,149,151,172,185,169,106,193,247,171,15,157, +109,50,61,113,94,178,170,70,77,251,0,236,35,202,158,82,118,109,142,253,32,236,211,202,206,245,157,144,187,83,179,114,111,74, +158,201,13,41,238,31,17,250,231,146,114,142,41,198,168,150,211,104,128,38,53,126,66,117,120,242,179,118,46,41,207,137,151,209, +225,127,8,91,89,235,139,146,198,210,34,119,83,248,92,104,197,208,97,53,104,32,50,169,105,136,17,129,149,231,117,49,41,215,121, +8,241,107,227,113,210,54,167,17,139,137,92,222,73,202,181,214,50,60,183,149,168,79,45,195,207,253,84,198,16,59,25,17,167,154, +232,189,164,90,7,246,155,199,229,249,125,152,148,117,24,239,53,104,57,171,245,165,104,139,145,162,30,150,197,222,247,176,117, +34,183,152,152,39,78,186,170,212,103,173,56,89,68,150,119,211,229,57,58,77,100,133,103,86,83,151,153,157,239,251,121,243,117, +252,203,124,166,26,115,37,41,239,233,241,45,24,163,241,49,131,145,20,237,128,159,155,225,51,165,88,143,150,101,157,184,222,118, +189,3,215,117,76,222,227,89,17,167,19,126,188,202,140,174,183,205,221,48,121,5,111,60,119,68,172,33,158,154,173,89,206,160,182, +223,29,243,250,59,230,245,121,55,138,168,89,220,161,186,144,179,226,94,213,148,28,17,109,151,208,102,91,122,93,84,47,218,58, +151,89,209,231,232,170,205,170,216,252,126,202,42,61,151,155,177,179,202,175,139,204,123,28,215,9,119,19,27,38,99,184,88,44,82, +132,95,139,196,10,180,162,80,47,217,135,142,88,190,227,206,12,122,110,104,187,225,65,223,107,56,101,219,223,116,212,106,88, +196,138,164,193,85,231,254,102,81,252,168,183,104,185,101,223,115,202,249,146,28,146,159,55,180,159,86,220,200,101,194,170,212, +237,160,159,214,255,195,193,183,131,252,158,32,176,195,253,78,197,30,178,131,146,239,212,66,15,177,150,182,92,203,86,104,77, +91,129,157,31,172,251,129,215,54,77,203,52,106,133,190,115,162,233,144,109,57,184,118,152,63,236,59,115,195,121,65,158,207,53, +54,29,216,126,131,103,221,59,215,116,208,242,75,118,101,126,50,59,139,37,175,154,247,189,138,147,63,138,210,229,111,92,191,213, +77,161,153,203,189,255,127,104,123,122,27,254,115,128,126,90,89,44,91,149,134,115,44,111,185,174,23,90,161,227,185,249,125,110, +169,226,5,220,187,98,5,216,131,158,5,124,134,93,23,25,75,123,239,2,246,81,187,58,173,28,248,54,118,22,249,41,201,87,44,119, +38,63,54,125,212,46,133,237,186,67,33,207,174,159,210,237,197,160,174,133,86,72,108,130,244,137,97,156,184,137,2,25,19,5,33,225, +236,77,20,113,112,39,138,5,28,92,126,29,38,54,73,139,167,22,152,37,105,149,74,118,16,236,175,88,51,1,69,248,98,109,74,150, +188,74,189,234,222,111,85,237,128,150,170,195,198,171,214,204,101,144,187,149,169,167,205,52,55,173,125,13,168,105,89,155,253, +62,59,196,164,182,85,29,63,89,67,220,155,218,140,99,53,219,229,1,168,179,77,253,64,221,246,79,146,89,182,43,118,104,83,196,22, +97,151,204,216,225,66,39,141,210,51,237,83,68,209,231,18,25,71,188,32,164,56,191,142,123,135,177,66,211,113,145,104,72,70,197, +43,29,35,163,106,5,199,40,93,117,170,54,119,71,212,16,149,53,170,94,25,67,93,84,129,98,158,59,136,184,200,33,234,185,114,113, +29,30,82,110,221,124,240,104,174,192,168,89,225,17,74,212,124,143,239,45,14,0,69,142,203,101,224,118,173,87,144,71,128,229,72, +75,71,75,220,227,163,254,113,212,54,28,243,203,124,246,240,136,19,144,201,175,171,251,200,172,215,202,124,118,189,238,59,252, +82,161,72,131,63,21,200,20,77,64,155,244,3,219,215,71,211,27,119,109,164,187,40,154,222,53,73,203,140,3,219,7,118,72,213,42,173, +111,32,154,158,196,147,24,38,178,244,194,208,190,104,154,30,99,90,97,39,20,14,205,176,2,250,227,90,97,20,205,16,156,168,170, +21,238,22,166,134,20,138,58,254,116,108,156,26,193,147,119,36,50,178,103,104,223,126,97,157,50,10,163,34,150,214,193,70,186,83, +90,90,91,107,100,239,94,114,75,83,88,166,45,98,35,183,106,221,137,238,36,105,26,195,159,238,103,115,145,211,167,141,75,49,237, +81,141,76,246,93,140,171,53,174,142,157,57,109,60,30,103,80,39,216,133,56,49,35,110,104,73,232,46,9,93,147,69,236,199,56,99,127, +129,139,9,198,62,0,95,129,171,224,124,146,177,31,193,75,41,249,110,75,234,89,222,108,155,223,30,252,57,223,252,254,208,105, +246,27,196,160,217,239,16,222,54,191,69,76,154,253,30,209,51,82,230,127,207,88,78,190,75,15,64,54,115,82,207,223,161,88,70,190, +103,139,119,228,156,156,151,127,191,232,202,159,191,243,24,57,57,31,127,47,34,53,86,188,123,101,100,174,252,91,233,111,138,244, +241,33,100,13,0,0,0,0}; //============================================================================== #define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \ diff --git a/modules/juce_gui_basics/native/juce_android_Windowing.cpp b/modules/juce_gui_basics/native/juce_android_Windowing.cpp index 18be24d4..7b1d1ec5 100644 --- a/modules/juce_gui_basics/native/juce_android_Windowing.cpp +++ b/modules/juce_gui_basics/native/juce_android_Windowing.cpp @@ -196,10 +196,6 @@ static const uint8 javaComponentPeerView[] = extern void juce_firebaseRemoteMessageSendError (void*, void*); #endif -#if JUCE_IN_APP_PURCHASES && JUCE_MODULE_AVAILABLE_juce_product_unlocking - extern void juce_inAppPurchaseCompleted (void*); -#endif - extern void juce_contentSharingCompleted (int); //============================================================================== diff --git a/modules/juce_gui_basics/native/juce_ios_ContentSharer.cpp b/modules/juce_gui_basics/native/juce_ios_ContentSharer.cpp index da10b2ad..f9c26a0d 100644 --- a/modules/juce_gui_basics/native/juce_ios_ContentSharer.cpp +++ b/modules/juce_gui_basics/native/juce_ios_ContentSharer.cpp @@ -164,9 +164,6 @@ private: if (auto* parentController = peer->controller) [parentController showViewController: controller.get() sender: parentController]; - - if (peer->view.window != nil) - peer->view.window.autoresizesSubviews = YES; } } diff --git a/modules/juce_gui_basics/native/juce_ios_FileChooser.mm b/modules/juce_gui_basics/native/juce_ios_FileChooser.mm index 4cea7ea0..ed481968 100644 --- a/modules/juce_gui_basics/native/juce_ios_FileChooser.mm +++ b/modules/juce_gui_basics/native/juce_ios_FileChooser.mm @@ -144,9 +144,6 @@ private: if (auto* parentController = peer->controller) [parentController showViewController: controller.get() sender: parentController]; - - if (peer->view.window != nil) - peer->view.window.autoresizesSubviews = YES; } } diff --git a/modules/juce_gui_basics/native/juce_ios_UIViewComponentPeer.mm b/modules/juce_gui_basics/native/juce_ios_UIViewComponentPeer.mm index 9f4b5480..e15f423b 100644 --- a/modules/juce_gui_basics/native/juce_ios_UIViewComponentPeer.mm +++ b/modules/juce_gui_basics/native/juce_ios_UIViewComponentPeer.mm @@ -600,7 +600,6 @@ UIViewComponentPeer::UIViewComponentPeer (Component& comp, const int windowStyle window.rootViewController = controller; window.hidden = true; - window.autoresizesSubviews = NO; window.transform = Orientations::getCGTransformFor (Desktop::getInstance().getCurrentOrientation()); window.opaque = component.isOpaque(); window.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent: 0]; diff --git a/modules/juce_gui_basics/native/juce_linux_X11_Windowing.cpp b/modules/juce_gui_basics/native/juce_linux_X11_Windowing.cpp index c44e331e..51068ad4 100644 --- a/modules/juce_gui_basics/native/juce_linux_X11_Windowing.cpp +++ b/modules/juce_gui_basics/native/juce_linux_X11_Windowing.cpp @@ -1526,6 +1526,9 @@ public: ScopedXLock xlock (display); XGetInputFocus (display, &focusedWindow, &revert); + if (focusedWindow == PointerRoot) + return false; + return isParentWindowOf (focusedWindow); } diff --git a/modules/juce_gui_basics/native/juce_mac_NSViewComponentPeer.mm b/modules/juce_gui_basics/native/juce_mac_NSViewComponentPeer.mm index b391fba6..4f7c30c9 100644 --- a/modules/juce_gui_basics/native/juce_mac_NSViewComponentPeer.mm +++ b/modules/juce_gui_basics/native/juce_mac_NSViewComponentPeer.mm @@ -24,6 +24,23 @@ ============================================================================== */ +//============================================================================== +#if defined (MAC_OS_X_VERSION_10_8) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_8) \ + && USE_COREGRAPHICS_RENDERING && JUCE_COREGRAPHICS_DRAW_ASYNC +static const juce::Identifier disableAsyncLayerBackedViewIdentifier { "disableAsyncLayerBackedView" }; + +void setComponentAsyncLayerBackedViewDisabled (juce::Component& comp, bool shouldDisableAsyncLayerBackedView) +{ + comp.getProperties().set (disableAsyncLayerBackedViewIdentifier, shouldDisableAsyncLayerBackedView); +} + +bool getComponentAsyncLayerBackedViewDisabled (juce::Component& comp) +{ + return comp.getProperties()[disableAsyncLayerBackedViewIdentifier]; +} +#endif + +//============================================================================== namespace juce { typedef void (*AppFocusChangeCallback)(); @@ -85,6 +102,15 @@ public: [view setPostsFrameChangedNotifications: YES]; + #if defined (MAC_OS_X_VERSION_10_8) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_8) \ + && USE_COREGRAPHICS_RENDERING && JUCE_COREGRAPHICS_DRAW_ASYNC + if (! getComponentAsyncLayerBackedViewDisabled (component)) + { + [view setWantsLayer: YES]; + [[view layer] setDrawsAsynchronously: YES]; + } + #endif + if (isSharedWindow) { window = [viewToAttachTo window]; @@ -106,13 +132,11 @@ public: [window setOpaque: component.isOpaque()]; - #if defined (MAC_OS_X_VERSION_10_14) && (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_14) if (! [window isOpaque]) [window setBackgroundColor: [NSColor clearColor]]; - #if defined (MAC_OS_X_VERSION_10_9) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_9) - [view setAppearance: [NSAppearance appearanceNamed: NSAppearanceNameAqua]]; - #endif + #if defined (MAC_OS_X_VERSION_10_9) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_9) + [view setAppearance: [NSAppearance appearanceNamed: NSAppearanceNameAqua]]; #endif [window setHasShadow: ((windowStyleFlags & windowHasDropShadow) != 0)]; @@ -923,7 +947,7 @@ public: // When windows are being resized, artificially throttling high-frequency repaints helps // to stop the event queue getting clogged, and keeps everything working smoothly. - // For some reason Logic also needs this throttling to recored parameter events correctly. + // For some reason Logic also needs this throttling to record parameter events correctly. if (msSinceLastRepaint < minimumRepaintInterval && shouldThrottleRepaint()) { startTimer (static_cast (minimumRepaintInterval - msSinceLastRepaint)); @@ -991,12 +1015,12 @@ public: bool canBecomeKeyWindow() { - return (getStyleFlags() & juce::ComponentPeer::windowIgnoresKeyPresses) == 0; + return component.isVisible() && (getStyleFlags() & juce::ComponentPeer::windowIgnoresKeyPresses) == 0; } bool canBecomeMainWindow() { - return dynamic_cast (&component) != nullptr; + return component.isVisible() && dynamic_cast (&component) != nullptr; } bool worksWhenModal() const @@ -1857,9 +1881,15 @@ private: static BOOL becomeFirstResponder (id self, SEL) { if (auto* owner = getOwner (self)) - owner->viewFocusGain(); + { + if (owner->canBecomeKeyWindow()) + { + owner->viewFocusGain(); + return YES; + } + } - return YES; + return NO; } static BOOL resignFirstResponder (id self, SEL) @@ -1975,7 +2005,17 @@ private: sendSuperclassMessage (self, @selector (becomeKeyWindow)); if (auto* owner = getOwner (self)) - owner->becomeKeyWindow(); + { + if (owner->canBecomeKeyWindow()) + { + owner->becomeKeyWindow(); + return; + } + + // this fixes a bug causing hidden windows to sometimes become visible when the app regains focus + if (! owner->getComponent().isVisible()) + [(NSWindow*) self orderOut: nil]; + } } static BOOL windowShouldClose (id self, SEL, id /*window*/) diff --git a/modules/juce_gui_basics/native/juce_mac_Windowing.mm b/modules/juce_gui_basics/native/juce_mac_Windowing.mm index b40684f5..ddc082a9 100644 --- a/modules/juce_gui_basics/native/juce_mac_Windowing.mm +++ b/modules/juce_gui_basics/native/juce_mac_Windowing.mm @@ -518,8 +518,14 @@ bool juce_areThereAnyAlwaysOnTopWindows() static void selectImageForDrawing (const Image& image) { [NSGraphicsContext saveGraphicsState]; + + #if (defined (MAC_OS_X_VERSION_10_10) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_10) [NSGraphicsContext setCurrentContext: [NSGraphicsContext graphicsContextWithCGContext: juce_getImageContext (image) flipped: false]]; + #else + [NSGraphicsContext setCurrentContext: [NSGraphicsContext graphicsContextWithGraphicsPort: juce_getImageContext (image) + flipped: false]]; + #endif } static void releaseImageAfterDrawing() diff --git a/modules/juce_gui_basics/native/juce_win32_FileChooser.cpp b/modules/juce_gui_basics/native/juce_win32_FileChooser.cpp index a7ac49ce..d708c860 100644 --- a/modules/juce_gui_basics/native/juce_win32_FileChooser.cpp +++ b/modules/juce_gui_basics/native/juce_win32_FileChooser.cpp @@ -34,7 +34,7 @@ namespace juce // the dialog box. This means that the actual native FileChooser HWND may // not have been created yet when the user deletes JUCE's FileChooser class. If this // occurs the Win32NativeFileChooser will still have a reference count of 1 and will -// simply delete itself immedietely once the HWND will have been created a while later. +// simply delete itself immediately once the HWND will have been created a while later. class Win32NativeFileChooser : public ReferenceCountedObject, private Thread { diff --git a/modules/juce_gui_basics/native/juce_win32_Windowing.cpp b/modules/juce_gui_basics/native/juce_win32_Windowing.cpp index 455ceb39..b9c217e8 100644 --- a/modules/juce_gui_basics/native/juce_win32_Windowing.cpp +++ b/modules/juce_gui_basics/native/juce_win32_Windowing.cpp @@ -56,7 +56,7 @@ extern void juce_repeatLastProcessPriority(); extern void juce_checkCurrentlyFocusedTopLevelWindow(); // in juce_TopLevelWindow.cpp extern bool juce_isRunningInWine(); -typedef bool (*CheckEventBlockedByModalComps) (const MSG&); +using CheckEventBlockedByModalComps = bool (*)(const MSG&); extern CheckEventBlockedByModalComps isEventBlockedByModalComps; static bool shouldDeactivateTitleBar = true; @@ -496,7 +496,7 @@ static double getGlobalDPI() #endif //============================================================================== -typedef void (*SettingChangeCallbackFunc) (void); +using SettingChangeCallbackFunc = void (*)(void); extern SettingChangeCallbackFunc settingChangeCallback; //============================================================================== @@ -1632,8 +1632,8 @@ public: scale = 1.0 / Desktop::getInstance().getDisplays().getMainDisplay().scale; #endif - const RECT r = { roundToInt (area.getX() * scale), roundToInt (area.getY() * scale), - roundToInt (area.getRight() * scale), roundToInt (area.getBottom() * scale) }; + auto scaled = area.toDouble() * scale; + auto r = RECTFromRectangle (scaled.getSmallestIntegerContainer()); InvalidateRect (hwnd, &r, FALSE); } diff --git a/modules/juce_gui_basics/properties/juce_MultiChoicePropertyComponent.h b/modules/juce_gui_basics/properties/juce_MultiChoicePropertyComponent.h index d10b56d9..b3eeaceb 100644 --- a/modules/juce_gui_basics/properties/juce_MultiChoicePropertyComponent.h +++ b/modules/juce_gui_basics/properties/juce_MultiChoicePropertyComponent.h @@ -55,7 +55,7 @@ public: These are the values that will be read and written to the valueToControl value. This array must contain the same number of items as the choices array - @param maxChoices the maxmimum number of values which can be selected at once. The default of + @param maxChoices the maximum number of values which can be selected at once. The default of -1 will not limit the number that can be selected */ MultiChoicePropertyComponent (const Value& valueToControl, @@ -73,7 +73,7 @@ public: These are the values that will be read and written to the valueToControl value. This array must contain the same number of items as the choices array - @param maxChoices the maxmimum number of values which can be selected at once. The default of + @param maxChoices the maximum number of values which can be selected at once. The default of -1 will not limit the number that can be selected */ MultiChoicePropertyComponent (ValueWithDefault& valueToControl, diff --git a/modules/juce_gui_basics/properties/juce_PropertyPanel.h b/modules/juce_gui_basics/properties/juce_PropertyPanel.h index 35d2e9d7..eeda9c5d 100644 --- a/modules/juce_gui_basics/properties/juce_PropertyPanel.h +++ b/modules/juce_gui_basics/properties/juce_PropertyPanel.h @@ -77,7 +77,7 @@ public: The components in the list will be owned by this object and will be automatically deleted later on when no longer needed. - To add properies without them being in a section, use addProperties(). + To add properties without them being in a section, use addProperties(). */ void addSection (const String& sectionTitle, const Array& newPropertyComponents, diff --git a/modules/juce_gui_basics/widgets/juce_ComboBox.cpp b/modules/juce_gui_basics/widgets/juce_ComboBox.cpp index cf59fa85..d20093a7 100644 --- a/modules/juce_gui_basics/widgets/juce_ComboBox.cpp +++ b/modules/juce_gui_basics/widgets/juce_ComboBox.cpp @@ -83,7 +83,7 @@ void ComboBox::addItem (const String& newItemText, int newItemId) // you can't add empty strings to the list.. jassert (newItemText.isNotEmpty()); - // IDs must be non-zero, as zero is used to indicate a lack of selecion. + // IDs must be non-zero, as zero is used to indicate a lack of selection. jassert (newItemId != 0); // you shouldn't use duplicate item IDs! @@ -489,6 +489,8 @@ void ComboBox::showPopupIfNotActive() // showPopup asynchronously, we are giving the other popups a chance to properly // close themselves MessageManager::callAsync ([safePointer]() mutable { if (safePointer != nullptr) safePointer->showPopup(); }); + + repaint(); } } diff --git a/modules/juce_gui_basics/widgets/juce_ComboBox.h b/modules/juce_gui_basics/widgets/juce_ComboBox.h index 043eb126..05876a7c 100644 --- a/modules/juce_gui_basics/widgets/juce_ComboBox.h +++ b/modules/juce_gui_basics/widgets/juce_ComboBox.h @@ -240,8 +240,8 @@ public: The text passed-in will be set as the current text regardless of whether it is one of the items in the list. If the current text isn't one of the - items, then getSelectedId() will return 0, otherwise it wil return - the approriate ID. + items, then getSelectedId() will return 0, otherwise it will return + the appropriate ID. @param newText the text to select @param notification determines the type of change notification that will diff --git a/modules/juce_gui_basics/widgets/juce_Slider.h b/modules/juce_gui_basics/widgets/juce_Slider.h index 8b9d6b26..7a723dbb 100644 --- a/modules/juce_gui_basics/widgets/juce_Slider.h +++ b/modules/juce_gui_basics/widgets/juce_Slider.h @@ -107,7 +107,7 @@ public: { notDragging, /**< Dragging is not active. */ absoluteDrag, /**< The dragging corresponds directly to the value that is displayed. */ - velocityDrag /**< The dragging value change is relative to the velocity of the mouse mouvement. */ + velocityDrag /**< The dragging value change is relative to the velocity of the mouse movement. */ }; //============================================================================== diff --git a/modules/juce_gui_basics/widgets/juce_TableHeaderComponent.h b/modules/juce_gui_basics/widgets/juce_TableHeaderComponent.h index 01057d51..e9a50b73 100644 --- a/modules/juce_gui_basics/widgets/juce_TableHeaderComponent.h +++ b/modules/juce_gui_basics/widgets/juce_TableHeaderComponent.h @@ -194,7 +194,7 @@ public: /** Triggers a re-sort of the table according to the current sort-column. - If you modifiy the table's contents, you can call this to signal that the table needs + If you modify the table's contents, you can call this to signal that the table needs to be re-sorted. (This doesn't do any sorting synchronously - it just asynchronously sends a call to the @@ -229,7 +229,7 @@ public: The index is an index from 0 to the number of columns that are currently visible (hidden ones are not counted). It returns a rectangle showing the position of the column relative - to this component's top-left. If the index is out-of-range, an empty rectangle is retrurned. + to this component's top-left. If the index is out-of-range, an empty rectangle is returned. */ Rectangle getColumnPosition (int index) const; @@ -382,7 +382,7 @@ public: highlightColourId = 0x1003830, /**< The colour of the table header background when the mouse is over or down above the the table header. It's up to the LookAndFeel to use a - variant of this colour to destiuish between + variant of this colour to distinguish between the down and hover state. */ }; diff --git a/modules/juce_gui_basics/widgets/juce_TreeView.h b/modules/juce_gui_basics/widgets/juce_TreeView.h index 734bc5e5..3c113a7d 100644 --- a/modules/juce_gui_basics/widgets/juce_TreeView.h +++ b/modules/juce_gui_basics/widgets/juce_TreeView.h @@ -532,7 +532,7 @@ public: /** Returns the index of this item in its parent's sub-items. */ int getIndexInParent() const noexcept; - /** Returns true if this item is the last of its parent's sub-itens. */ + /** Returns true if this item is the last of its parent's sub-items. */ bool isLastOfSiblings() const noexcept; /** Creates a string that can be used to uniquely retrieve this item in the tree. @@ -842,8 +842,8 @@ public: linesColourId = 0x1000501, /**< The colour to draw the lines with.*/ dragAndDropIndicatorColourId = 0x1000502, /**< The colour to use for the drag-and-drop target position indicator. */ selectedItemBackgroundColourId = 0x1000503, /**< The colour to use to fill the background of any selected items. */ - oddItemsColourId = 0x1000504, /**< The colour to use to fill the backround of the odd numbered items. */ - evenItemsColourId = 0x1000505 /**< The colour to use to fill the backround of the even numbered items. */ + oddItemsColourId = 0x1000504, /**< The colour to use to fill the background of the odd numbered items. */ + evenItemsColourId = 0x1000505 /**< The colour to use to fill the background of the even numbered items. */ }; //============================================================================== diff --git a/modules/juce_gui_basics/windows/juce_AlertWindow.cpp b/modules/juce_gui_basics/windows/juce_AlertWindow.cpp index 755d1dc0..a4376f7e 100644 --- a/modules/juce_gui_basics/windows/juce_AlertWindow.cpp +++ b/modules/juce_gui_basics/windows/juce_AlertWindow.cpp @@ -63,7 +63,7 @@ AlertWindow::~AlertWindow() for (auto* t : textBoxes) t->setWantsKeyboardFocus (false); - // Giveaway focus before removing the editors, so that any TextEditor + // Give away focus before removing the editors, so that any TextEditor // with focus has a chance to dismiss native keyboard if shown. if (hasKeyboardFocus (true)) Component::unfocusAllComponents(); diff --git a/modules/juce_gui_basics/windows/juce_DialogWindow.h b/modules/juce_gui_basics/windows/juce_DialogWindow.h index 29ec188b..92583f74 100644 --- a/modules/juce_gui_basics/windows/juce_DialogWindow.h +++ b/modules/juce_gui_basics/windows/juce_DialogWindow.h @@ -153,7 +153,7 @@ public: //============================================================================== /** Easy way of quickly showing a dialog box containing a given component. - Note: This method has been superceded by the DialogWindow::LaunchOptions structure, + Note: This method has been superseded by the DialogWindow::LaunchOptions structure, which does the same job with some extra flexibility. The showDialog method is here for backwards compatibility, but please use DialogWindow::LaunchOptions in new code. @@ -199,7 +199,7 @@ public: #if JUCE_MODAL_LOOPS_PERMITTED || DOXYGEN /** Easy way of quickly showing a dialog box containing a given component. - Note: This method has been superceded by the DialogWindow::LaunchOptions structure, + Note: This method has been superseded by the DialogWindow::LaunchOptions structure, which does the same job with some extra flexibility. The showDialog method is here for backwards compatibility, but please use DialogWindow::LaunchOptions in new code. diff --git a/modules/juce_gui_basics/windows/juce_ResizableWindow.h b/modules/juce_gui_basics/windows/juce_ResizableWindow.h index 473fdcee..cf1ab85a 100644 --- a/modules/juce_gui_basics/windows/juce_ResizableWindow.h +++ b/modules/juce_gui_basics/windows/juce_ResizableWindow.h @@ -159,7 +159,7 @@ public: A pointer to the object you pass in will be kept, but it won't be deleted by this object, so it's the caller's responsibility to manage it. - If you pass a nullptr, then no contraints will be placed on the positioning of the window. + If you pass a nullptr, then no constraints will be placed on the positioning of the window. */ void setConstrainer (ComponentBoundsConstrainer* newConstrainer); diff --git a/modules/juce_gui_extra/code_editor/juce_CodeEditorComponent.h b/modules/juce_gui_extra/code_editor/juce_CodeEditorComponent.h index 6810abc2..bde97610 100644 --- a/modules/juce_gui_extra/code_editor/juce_CodeEditorComponent.h +++ b/modules/juce_gui_extra/code_editor/juce_CodeEditorComponent.h @@ -337,7 +337,7 @@ public: */ virtual void performPopupMenuAction (int menuItemID); - /** Specifies a commmand-manager which the editor will notify whenever the state + /** Specifies a command-manager which the editor will notify whenever the state of any of its commands changes. If you're making use of the editor's ApplicationCommandTarget interface, then you should also use this to tell it which command manager it should use. Make diff --git a/modules/juce_gui_extra/embedding/juce_ScopedDPIAwarenessDisabler.h b/modules/juce_gui_extra/embedding/juce_ScopedDPIAwarenessDisabler.h index a769fba8..4894cb13 100644 --- a/modules/juce_gui_extra/embedding/juce_ScopedDPIAwarenessDisabler.h +++ b/modules/juce_gui_extra/embedding/juce_ScopedDPIAwarenessDisabler.h @@ -36,11 +36,13 @@ namespace juce when it goes out of scope. If you create one of these before creating a top-level window, the window - will be DPI unaware and bitmap strectched by the OS on a display with >100% + will be DPI unaware and bitmap stretched by the OS on a display with >100% scaling. You shouldn't use this unless you really know what you are doing and are dealing with native HWNDs. + + @tags{GUI} */ class JUCE_API ScopedDPIAwarenessDisabler { diff --git a/modules/juce_gui_extra/juce_gui_extra.h b/modules/juce_gui_extra/juce_gui_extra.h index 22361051..705bff90 100644 --- a/modules/juce_gui_extra/juce_gui_extra.h +++ b/modules/juce_gui_extra/juce_gui_extra.h @@ -24,6 +24,7 @@ ============================================================================== */ + /******************************************************************************* The block below describes the properties of this module, and is read by the Projucer to automatically generate project code that uses it. @@ -33,16 +34,16 @@ BEGIN_JUCE_MODULE_DECLARATION - ID: juce_gui_extra - vendor: juce - version: 5.4.5 - name: JUCE extended GUI classes - description: Miscellaneous GUI classes for specialised tasks. - website: http://www.juce.com/juce - license: GPL/Commercial + ID: juce_gui_extra + vendor: juce + version: 5.4.6 + name: JUCE extended GUI classes + description: Miscellaneous GUI classes for specialised tasks. + website: http://www.juce.com/juce + license: GPL/Commercial - dependencies: juce_gui_basics - OSXFrameworks: WebKit + dependencies: juce_gui_basics + OSXFrameworks: WebKit END_JUCE_MODULE_DECLARATION diff --git a/modules/juce_gui_extra/misc/juce_BubbleMessageComponent.h b/modules/juce_gui_extra/misc/juce_BubbleMessageComponent.h index eaa29f7e..a3ad36aa 100644 --- a/modules/juce_gui_extra/misc/juce_BubbleMessageComponent.h +++ b/modules/juce_gui_extra/misc/juce_BubbleMessageComponent.h @@ -70,7 +70,7 @@ public: @param position the coords of the object to point to @param message the text to display @param numMillisecondsBeforeRemoving how long to leave it on the screen before removing itself - from its parent compnent. If this is 0 or less, it + from its parent component. If this is 0 or less, it will stay there until manually removed. @param removeWhenMouseClicked if this is true, the bubble will disappear as soon as a mouse button is pressed (anywhere on the screen) @@ -93,7 +93,7 @@ public: @param component the component that you want to point at @param message the text to display @param numMillisecondsBeforeRemoving how long to leave it on the screen before removing itself - from its parent compnent. If this is 0 or less, it + from its parent component. If this is 0 or less, it will stay there until manually removed. @param removeWhenMouseClicked if this is true, the bubble will disappear as soon as a mouse button is pressed (anywhere on the screen) diff --git a/modules/juce_gui_extra/misc/juce_ColourSelector.cpp b/modules/juce_gui_extra/misc/juce_ColourSelector.cpp index 976b5982..5c98a4e6 100644 --- a/modules/juce_gui_extra/misc/juce_ColourSelector.cpp +++ b/modules/juce_gui_extra/misc/juce_ColourSelector.cpp @@ -302,6 +302,85 @@ private: JUCE_DECLARE_NON_COPYABLE (SwatchComponent) }; +//============================================================================== +class ColourSelector::ColourPreviewComp : public Component +{ +public: + ColourPreviewComp (ColourSelector& cs, bool isEditable) + : owner (cs) + { + colourLabel.setFont (labelFont); + colourLabel.setJustificationType (Justification::centred); + + if (isEditable) + { + colourLabel.setEditable (true); + + colourLabel.onEditorShow = [this] + { + if (auto* ed = colourLabel.getCurrentTextEditor()) + ed->setInputRestrictions ((owner.flags & showAlphaChannel) ? 8 : 6, "1234567890ABCDEFabcdef"); + }; + + colourLabel.onEditorHide = [this] + { + updateColourIfNecessary (colourLabel.getText()); + }; + } + + addAndMakeVisible (colourLabel); + } + + void updateIfNeeded() + { + auto newColour = owner.getCurrentColour(); + + if (currentColour != newColour) + { + currentColour = newColour; + auto textColour = (Colours::white.overlaidWith (currentColour).contrasting()); + + colourLabel.setColour (Label::textColourId, textColour); + colourLabel.setColour (Label::textWhenEditingColourId, textColour); + colourLabel.setText (currentColour.toDisplayString ((owner.flags & showAlphaChannel) != 0), dontSendNotification); + + labelWidth = labelFont.getStringWidth (colourLabel.getText()); + + repaint(); + } + } + + void paint (Graphics& g) override + { + g.fillCheckerBoard (getLocalBounds().toFloat(), 10.0f, 10.0f, + Colour (0xffdddddd).overlaidWith (currentColour), + Colour (0xffffffff).overlaidWith (currentColour)); + } + + void resized() override + { + colourLabel.centreWithSize (labelWidth + 10, (int) labelFont.getHeight() + 10); + } + +private: + void updateColourIfNecessary (const String& newColourString) + { + auto newColour = Colour::fromString (newColourString); + + if (newColour != currentColour) + owner.setCurrentColour (newColour); + } + + ColourSelector& owner; + + Colour currentColour; + Font labelFont { 14.0f, Font::bold }; + int labelWidth = 0; + Label colourLabel; + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ColourPreviewComp) +}; + //============================================================================== ColourSelector::ColourSelector (int sectionsToShow, int edge, int gapAroundColourSpaceComponent) : colour (Colours::white), @@ -313,6 +392,12 @@ ColourSelector::ColourSelector (int sectionsToShow, int edge, int gapAroundColou updateHSV(); + if ((flags & showColourAtTop) != 0) + { + previewComponent.reset (new ColourPreviewComp (*this, (flags & editableColour) != 0)); + addAndMakeVisible (previewComponent.get()); + } + if ((flags & showSliders) != 0) { sliders[0].reset (new ColourComponentSlider (TRANS ("red"))); @@ -418,8 +503,8 @@ void ColourSelector::update (NotificationType notification) hueSelector->updateIfNeeded(); } - if ((flags & showColourAtTop) != 0) - repaint (previewArea); + if (previewComponent != nullptr) + previewComponent->updateIfNeeded(); if (notification != dontSendNotification) sendChangeMessage(); @@ -433,20 +518,6 @@ void ColourSelector::paint (Graphics& g) { g.fillAll (findColour (backgroundColourId)); - if ((flags & showColourAtTop) != 0) - { - auto currentColour = getCurrentColour(); - - g.fillCheckerBoard (previewArea.toFloat(), 10.0f, 10.0f, - Colour (0xffdddddd).overlaidWith (currentColour), - Colour (0xffffffff).overlaidWith (currentColour)); - - g.setColour (Colours::white.overlaidWith (currentColour).contrasting()); - g.setFont (Font (14.0f, Font::bold)); - g.drawText (currentColour.toDisplayString ((flags & showAlphaChannel) != 0), - previewArea, Justification::centred, false); - } - if ((flags & showSliders) != 0) { g.setColour (findColour (labelTextColourId)); @@ -475,7 +546,8 @@ void ColourSelector::resized() const int sliderSpace = ((flags & showSliders) != 0) ? jmin (22 * numSliders + edgeGap, proportionOfHeight (0.3f)) : 0; const int topSpace = ((flags & showColourAtTop) != 0) ? jmin (30 + edgeGap * 2, proportionOfHeight (0.2f)) : edgeGap; - previewArea.setBounds (edgeGap, edgeGap, getWidth() - edgeGap * 2, topSpace - edgeGap * 2); + if (previewComponent != nullptr) + previewComponent->setBounds (edgeGap, edgeGap, getWidth() - edgeGap * 2, topSpace - edgeGap * 2); int y = topSpace; diff --git a/modules/juce_gui_extra/misc/juce_ColourSelector.h b/modules/juce_gui_extra/misc/juce_ColourSelector.h index fb233ec3..a7c62fe0 100644 --- a/modules/juce_gui_extra/misc/juce_ColourSelector.h +++ b/modules/juce_gui_extra/misc/juce_ColourSelector.h @@ -49,8 +49,9 @@ public: showAlphaChannel = 1 << 0, /**< if set, the colour's alpha channel can be changed as well as its RGB. */ showColourAtTop = 1 << 1, /**< if set, a swatch of the colour is shown at the top of the component. */ - showSliders = 1 << 2, /**< if set, RGB sliders are shown at the bottom of the component. */ - showColourspace = 1 << 3 /**< if set, a big HSV selector is shown. */ + editableColour = 1 << 2, /**< if set, the colour shows at the top of the component is editable. */ + showSliders = 1 << 3, /**< if set, RGB sliders are shown at the bottom of the component. */ + showColourspace = 1 << 4 /**< if set, a big HSV selector is shown. */ }; //============================================================================== @@ -137,6 +138,7 @@ public: // These need to be public otherwise the Projucer's live-build engine will complain class ColourSpaceView; class HueSelectorComp; + class ColourPreviewComp; private: //============================================================================== @@ -147,10 +149,10 @@ private: std::unique_ptr sliders[4]; std::unique_ptr colourSpace; std::unique_ptr hueSelector; + std::unique_ptr previewComponent; OwnedArray swatchComponents; const int flags; int edgeGap; - Rectangle previewArea; void setHue (float newH); void setSV (float newS, float newV); diff --git a/modules/juce_gui_extra/misc/juce_PushNotifications.h b/modules/juce_gui_extra/misc/juce_PushNotifications.h index 742486a5..4b39f2c8 100644 --- a/modules/juce_gui_extra/misc/juce_PushNotifications.h +++ b/modules/juce_gui_extra/misc/juce_PushNotifications.h @@ -276,7 +276,7 @@ public: bool localOnly = true; /**< Optional: whether or not the notification should bridge to other devices. Available from Android API 20 or above. */ - bool ongoing = false; /**< Optional: If true, then it cannot be dismissed by the user and it must be dimissed manually. + bool ongoing = false; /**< Optional: If true, then it cannot be dismissed by the user and it must be dismissed manually. Typically used for ongoing background tasks that the user is actively engaged with. To dismiss such notification, you need to call removeDeliveredNotification() or removeAllDeliveredNotifications(). */ @@ -389,7 +389,7 @@ public: { using Action = Notification::Action; - /** Describes a category of a notification. Each category has a unique idenfifier + /** Describes a category of a notification. Each category has a unique identifier and a list of associated actions. Note that the OS may allow only a limited number of actions to be presented, so always present most important actions first. @@ -634,7 +634,7 @@ public: @param isLocalNotification If the notification is local @param notification The notification - @param actionIdentifier A String identifiing the action + @param actionIdentifier A String identifying the action @param optionalResponse Text response a user inputs for notifications with a text input. Empty for notifications without a text input option. diff --git a/modules/juce_gui_extra/native/juce_android_PushNotifications.cpp b/modules/juce_gui_extra/native/juce_android_PushNotifications.cpp index 9d77b2cb..69c65003 100644 --- a/modules/juce_gui_extra/native/juce_android_PushNotifications.cpp +++ b/modules/juce_gui_extra/native/juce_android_PushNotifications.cpp @@ -1303,7 +1303,7 @@ struct PushNotifications::Pimpl auto classAsString = LocalRef ((jstring) env->CallObjectMethod (objectClass, JavaClass.getName)); // Note: It seems that Firebase delivers values as strings always, so this check is rather unnecessary, - // at least untill they change the behaviour. + // at least until they change the behaviour. var value = juceString (classAsString) == "java.lang.Bundle" ? bundleToVar (object) : var (juceString (objectAsString.get())); dynamicObject->setProperty (juceString (key.get()), value); } @@ -1399,7 +1399,7 @@ struct PushNotifications::Pimpl propertiesDynamicObject->setProperty ("titleLocalizationKey", juceString (titleLocalizationKey.get())); propertiesDynamicObject->setProperty ("bodyLocalizationArgs", javaStringArrayToJuce (bodyLocalizationArgs)); propertiesDynamicObject->setProperty ("titleLocalizationArgs", javaStringArrayToJuce (titleLocalizationArgs)); - propertiesDynamicObject->setProperty ("link", link.get() == nullptr ? juceString ((jstring) env->CallObjectMethod (link, AndroidUri.toString)) : String()); + propertiesDynamicObject->setProperty ("link", link.get() != nullptr ? juceString ((jstring) env->CallObjectMethod (link, AndroidUri.toString)) : String()); } n.properties = var (propertiesDynamicObject.get()); @@ -1561,7 +1561,7 @@ struct JuceFirebaseInstanceIdService DECLARE_JNI_CLASS (InstanceIdService, "com/roli/juce/JuceFirebaseInstanceIdService") #undef JNI_CLASS_MEMBERS - static void JNICALL tokenRefreshed (void* token) + static void JNICALL tokenRefreshed (JNIEnv*, jobject /*instanceIdService*/, void* token) { if (auto* instance = PushNotifications::getInstanceWithoutCreating()) instance->pimpl->notifyListenersTokenRefreshed (juceString (static_cast (token))); @@ -1577,9 +1577,9 @@ struct JuceFirebaseMessagingService { #define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \ CALLBACK (remoteNotificationReceived, "firebaseRemoteMessageReceived", "(Lcom/google/firebase/messaging/RemoteMessage;)V") \ - CALLBACK (remoteMessagesDeleted, "firebaseRemoteMessagesDeleted", "()V") \ - CALLBACK (remoteMessageSent, "firebaseRemoteMessageSent", "(Ljava/lang/String;)V") \ - CALLBACK (remoteMessageSendError, "firebaseRemoteMessageSendError", "(Ljava/lang/String;Ljava/lang/String;)V") + CALLBACK (remoteMessagesDeleted, "firebaseRemoteMessagesDeleted", "()V") \ + CALLBACK (remoteMessageSent, "firebaseRemoteMessageSent", "(Ljava/lang/String;)V") \ + CALLBACK (remoteMessageSendError, "firebaseRemoteMessageSendError", "(Ljava/lang/String;Ljava/lang/String;)V") DECLARE_JNI_CLASS (MessagingService, "com/roli/juce/JuceFirebaseMessagingService") #undef JNI_CLASS_MEMBERS diff --git a/modules/juce_gui_extra/native/juce_ios_PushNotifications.cpp b/modules/juce_gui_extra/native/juce_ios_PushNotifications.cpp index 0aa43b6c..5f0aee26 100644 --- a/modules/juce_gui_extra/native/juce_ios_PushNotifications.cpp +++ b/modules/juce_gui_extra/native/juce_ios_PushNotifications.cpp @@ -174,7 +174,7 @@ namespace PushNotificationsDelegateDetails } // request - // each notification on iOS 10 needs to have an identifer, otherwise it will not show up + // each notification on iOS 10 needs to have an identifier, otherwise it will not show up jassert (n.identifier.isNotEmpty()); UNNotificationRequest* request = [UNNotificationRequest requestWithIdentifier: juceStringToNS (n.identifier) content: content @@ -300,7 +300,9 @@ namespace PushNotificationsDelegateDetails if (n.fireDate != nil) { NSDate* dateNow = [NSDate date]; - notif.triggerIntervalSec = [dateNow timeIntervalSinceDate: n.fireDate]; + NSDate* fireDate = n.fireDate; + + notif.triggerIntervalSec = [dateNow timeIntervalSinceDate: fireDate]; } notif.soundToPlay = URL (nsStringToJuce (n.soundName)); @@ -841,12 +843,22 @@ struct PushNotifications::Pimpl : private PushNotificationsDelegate void registeredForRemoteNotifications (NSData* deviceTokenToUse) override { - NSString* deviceTokenString = [[[[deviceTokenToUse description] - stringByReplacingOccurrencesOfString: nsStringLiteral ("<") withString: nsStringLiteral ("")] - stringByReplacingOccurrencesOfString: nsStringLiteral (">") withString: nsStringLiteral ("")] - stringByReplacingOccurrencesOfString: nsStringLiteral (" ") withString: nsStringLiteral ("")]; + deviceToken = [deviceTokenToUse]() -> String + { + auto length = deviceTokenToUse.length; + + if (auto* buffer = (const unsigned char*) deviceTokenToUse.bytes) + { + NSMutableString* hexString = [NSMutableString stringWithCapacity: (length * 2)]; - deviceToken = nsStringToJuce (deviceTokenString); + for (NSUInteger i = 0; i < length; ++i) + [hexString appendFormat:@"%02x", buffer[i]]; + + return nsStringToJuce ([hexString copy]); + } + + return {}; + }(); initialised = true; diff --git a/modules/juce_gui_extra/native/juce_mac_PushNotifications.cpp b/modules/juce_gui_extra/native/juce_mac_PushNotifications.cpp index c23d8e25..3d017be1 100644 --- a/modules/juce_gui_extra/native/juce_mac_PushNotifications.cpp +++ b/modules/juce_gui_extra/native/juce_mac_PushNotifications.cpp @@ -151,7 +151,9 @@ namespace PushNotificationsDelegateDetailsOsx else { NSDate* dateNow = [NSDate date]; - notif.triggerIntervalSec = [dateNow timeIntervalSinceDate: n.deliveryDate]; + NSDate* deliveryDate = n.deliveryDate; + + notif.triggerIntervalSec = [dateNow timeIntervalSinceDate: deliveryDate]; } notif.soundToPlay = URL (nsStringToJuce (n.soundName)); @@ -367,7 +369,7 @@ struct PushNotifications::Pimpl : private PushNotificationsDelegate NSRemoteNotificationType types = NSUInteger ((bool) settings.allowBadge); if (isAtLeastMountainLion) - types |= ((bool) settings.allowSound << 1 | (bool) settings.allowAlert << 2); + types |= (NSUInteger) ((bool) settings.allowSound << 1 | (bool) settings.allowAlert << 2); [[NSApplication sharedApplication] registerForRemoteNotificationTypes: types]; } @@ -469,12 +471,22 @@ struct PushNotifications::Pimpl : private PushNotificationsDelegate //PushNotificationsDelegate void registeredForRemoteNotifications (NSData* deviceTokenToUse) override { - auto deviceTokenString = [[[[deviceTokenToUse description] - stringByReplacingOccurrencesOfString: nsStringLiteral ("<") withString: nsStringLiteral ("")] - stringByReplacingOccurrencesOfString: nsStringLiteral (">") withString: nsStringLiteral ("")] - stringByReplacingOccurrencesOfString: nsStringLiteral (" ") withString: nsStringLiteral ("")]; + deviceToken = [deviceTokenToUse]() -> String + { + auto length = deviceTokenToUse.length; + + if (auto* buffer = (const unsigned char*) deviceTokenToUse.bytes) + { + NSMutableString* hexString = [NSMutableString stringWithCapacity: (length * 2)]; - deviceToken = nsStringToJuce (deviceTokenString); + for (NSUInteger i = 0; i < length; ++i) + [hexString appendFormat:@"%02x", buffer[i]]; + + return nsStringToJuce ([hexString copy]); + } + + return {}; + }(); initialised = true; @@ -520,7 +532,7 @@ struct PushNotifications::Pimpl : private PushNotificationsDelegate } } - bool shouldPresentNotification (NSUserNotification* notification) override { return true; } + bool shouldPresentNotification (NSUserNotification*) override { return true; } void subscribeToTopic (const String& topic) { ignoreUnused (topic); } void unsubscribeFromTopic (const String& topic) { ignoreUnused (topic); } diff --git a/modules/juce_gui_extra/native/juce_mac_SystemTrayIcon.cpp b/modules/juce_gui_extra/native/juce_mac_SystemTrayIcon.cpp index 1a0feedd..3086162b 100644 --- a/modules/juce_gui_extra/native/juce_mac_SystemTrayIcon.cpp +++ b/modules/juce_gui_extra/native/juce_mac_SystemTrayIcon.cpp @@ -27,45 +27,38 @@ namespace juce { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunguarded-availability" +#if JUCE_CLANG && defined (MAC_OS_X_VERSION_10_14) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_14 + #pragma clang diagnostic ignored "-Wdeprecated-declarations" +#endif + extern NSMenu* createNSMenu (const PopupMenu&, const String& name, int topLevelMenuId, int topLevelIndex, bool addDelegate); -class SystemTrayIconComponent::Pimpl : private Timer +//============================================================================== +struct StatusItemContainer : public Timer { -public: //============================================================================== - Pimpl (SystemTrayIconComponent& iconComp, const Image& im) + StatusItemContainer (SystemTrayIconComponent& iconComp, const Image& im) : owner (iconComp), statusIcon (imageToNSImage (im)) { - static ButtonEventForwarderClass cls; - eventForwarder.reset ([cls.createInstance() init]); - ButtonEventForwarderClass::setOwner (eventForwarder.get(), this); + } - configureIcon(); + virtual void configureIcon() = 0; + virtual void setHighlighted (bool shouldHighlight) = 0; - statusItem.reset ([[[NSStatusBar systemStatusBar] statusItemWithLength: NSSquareStatusItemLength] retain]); - auto button = [statusItem.get() button]; - button.image = statusIcon.get(); - button.target = eventForwarder.get(); - button.action = @selector (handleEvent:); - #if defined (MAC_OS_X_VERSION_10_12) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_12 - [button sendActionOn: NSEventMaskLeftMouseDown | NSEventMaskRightMouseDown | NSEventMaskScrollWheel]; - #else - [button sendActionOn: NSLeftMouseDownMask | NSRightMouseDownMask | NSScrollWheelMask]; - #endif + //============================================================================== + void setIconSize() + { + [statusIcon.get() setSize: NSMakeSize (20.0f, 20.0f)]; } - //============================================================================== void updateIcon (const Image& newImage) { statusIcon.reset (imageToNSImage (newImage)); + setIconSize(); configureIcon(); - [statusItem.get() button].image = statusIcon.get(); - } - - void setHighlighted (bool shouldHighlight) - { - [[statusItem.get() button] setHighlighted: shouldHighlight]; } void showMenu (const PopupMenu& menu) @@ -75,28 +68,64 @@ public: setHighlighted (true); stopTimer(); - // There's currently no good alternative to this... - #if JUCE_CLANG && ! (defined (MAC_OS_X_VERSION_10_16) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_16) - #pragma clang diagnostic push - #pragma clang diagnostic ignored "-Wdeprecated-declarations" - #define JUCE_DEPRECATION_IGNORED 1 - #endif - + // There's currently no good alternative to this. [statusItem.get() popUpStatusItemMenu: m]; - #if JUCE_DEPRECATION_IGNORED - #pragma clang diagnostic pop - #undef JUCE_DEPRECATION_IGNORED - #endif - startTimer (1); } } //============================================================================== - NSStatusItem* getStatusItem() + void timerCallback() override + { + stopTimer(); + setHighlighted (false); + } + + //============================================================================== + SystemTrayIconComponent& owner; + + std::unique_ptr statusItem; + std::unique_ptr statusIcon; + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (StatusItemContainer) +}; + +//============================================================================== +struct ButtonBasedStatusItem : public StatusItemContainer +{ + //============================================================================== + ButtonBasedStatusItem (SystemTrayIconComponent& iconComp, const Image& im) + : StatusItemContainer (iconComp, im) + { + static ButtonEventForwarderClass cls; + eventForwarder.reset ([cls.createInstance() init]); + ButtonEventForwarderClass::setOwner (eventForwarder.get(), this); + + setIconSize(); + configureIcon(); + + statusItem.reset ([[[NSStatusBar systemStatusBar] statusItemWithLength: NSSquareStatusItemLength] retain]); + auto button = [statusItem.get() button]; + button.image = statusIcon.get(); + button.target = eventForwarder.get(); + button.action = @selector (handleEvent:); + #if defined (MAC_OS_X_VERSION_10_12) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_12 + [button sendActionOn: NSEventMaskLeftMouseDown | NSEventMaskRightMouseDown | NSEventMaskScrollWheel]; + #else + [button sendActionOn: NSLeftMouseDownMask | NSRightMouseDownMask | NSScrollWheelMask]; + #endif + } + + void configureIcon() override { - return statusItem.get(); + [statusIcon.get() setTemplate: true]; + [statusItem.get() button].image = statusIcon.get(); + } + + void setHighlighted (bool shouldHighlight) override + { + [[statusItem.get() button] setHighlighted: shouldHighlight]; } //============================================================================== @@ -152,35 +181,21 @@ public: } } -private: - //============================================================================== - void configureIcon() - { - [statusIcon.get() setSize: NSMakeSize (20.0f, 20.0f)]; - [statusIcon.get() setTemplate: true]; - } - - void timerCallback() override - { - stopTimer(); - setHighlighted (false); - } - //============================================================================== class ButtonEventForwarderClass : public ObjCClass { public: ButtonEventForwarderClass() : ObjCClass ("JUCEButtonEventForwarderClass_") { - addIvar ("owner"); + addIvar ("owner"); addMethod (@selector (handleEvent:), handleEvent, "v@:@"); registerClass(); } - static Pimpl* getOwner (id self) { return getIvar (self, "owner"); } - static void setOwner (id self, Pimpl* owner) { object_setInstanceVariable (self, "owner", owner); } + static ButtonBasedStatusItem* getOwner (id self) { return getIvar (self, "owner"); } + static void setOwner (id self, ButtonBasedStatusItem* owner) { object_setInstanceVariable (self, "owner", owner); } private: static void handleEvent (id self, SEL, id) @@ -191,14 +206,190 @@ private: }; //============================================================================== - SystemTrayIconComponent& owner; - std::unique_ptr statusItem; std::unique_ptr eventForwarder; - std::unique_ptr statusIcon; +}; - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Pimpl) +//============================================================================== +struct ViewBasedStatusItem : public StatusItemContainer +{ + //============================================================================== + ViewBasedStatusItem (SystemTrayIconComponent& iconComp, const Image& im) + : StatusItemContainer (iconComp, im) + { + static SystemTrayViewClass cls; + view.reset ([cls.createInstance() init]); + SystemTrayViewClass::setOwner (view.get(), this); + SystemTrayViewClass::setImage (view.get(), statusIcon.get()); + + setIconSize(); + + statusItem.reset ([[[NSStatusBar systemStatusBar] statusItemWithLength: NSSquareStatusItemLength] retain]); + [statusItem.get() setView: view.get()]; + + SystemTrayViewClass::frameChanged (view.get(), SEL(), nullptr); + + [[NSNotificationCenter defaultCenter] addObserver: view.get() + selector: @selector (frameChanged:) + name: NSWindowDidMoveNotification + object: nil]; + } + + ~ViewBasedStatusItem() override + { + [[NSNotificationCenter defaultCenter] removeObserver: view.get()]; + [[NSStatusBar systemStatusBar] removeStatusItem: statusItem.get()]; + SystemTrayViewClass::setOwner (view.get(), nullptr); + SystemTrayViewClass::setImage (view.get(), nil); + } + + void configureIcon() override + { + SystemTrayViewClass::setImage (view.get(), statusIcon.get()); + [statusItem.get() setView: view.get()]; + } + + void setHighlighted (bool shouldHighlight) override + { + isHighlighted = shouldHighlight; + [view.get() setNeedsDisplay: true]; + } + + //============================================================================== + void handleStatusItemAction (NSEvent* e) + { + NSEventType type = [e type]; + + const bool isLeft = (type == NSEventTypeLeftMouseDown || type == NSEventTypeLeftMouseUp); + const bool isRight = (type == NSEventTypeRightMouseDown || type == NSEventTypeRightMouseUp); + + if (owner.isCurrentlyBlockedByAnotherModalComponent()) + { + if (isLeft || isRight) + if (auto* current = Component::getCurrentlyModalComponent()) + current->inputAttemptWhenModal(); + } + else + { + auto eventMods = ComponentPeer::getCurrentModifiersRealtime(); + + if (([e modifierFlags] & NSEventModifierFlagCommand) != 0) + eventMods = eventMods.withFlags (ModifierKeys::commandModifier); + + auto now = Time::getCurrentTime(); + auto mouseSource = Desktop::getInstance().getMainMouseSource(); + auto pressure = (float) e.pressure; + + if (isLeft || isRight) // Only mouse up is sent by the OS, so simulate a down/up + { + setHighlighted (true); + startTimer (150); + + owner.mouseDown (MouseEvent (mouseSource, {}, + eventMods.withFlags (isLeft ? ModifierKeys::leftButtonModifier + : ModifierKeys::rightButtonModifier), + pressure, MouseInputSource::invalidOrientation, MouseInputSource::invalidRotation, + MouseInputSource::invalidTiltX, MouseInputSource::invalidTiltY, + &owner, &owner, now, {}, now, 1, false)); + + owner.mouseUp (MouseEvent (mouseSource, {}, eventMods.withoutMouseButtons(), pressure, + MouseInputSource::invalidOrientation, MouseInputSource::invalidRotation, + MouseInputSource::invalidTiltX, MouseInputSource::invalidTiltY, + &owner, &owner, now, {}, now, 1, false)); + } + else if (type == NSEventTypeMouseMoved) + { + owner.mouseMove (MouseEvent (mouseSource, {}, eventMods, pressure, + MouseInputSource::invalidOrientation, MouseInputSource::invalidRotation, + MouseInputSource::invalidTiltX, MouseInputSource::invalidTiltY, + &owner, &owner, now, {}, now, 1, false)); + } + } + } + + //============================================================================== + struct SystemTrayViewClass : public ObjCClass + { + SystemTrayViewClass() : ObjCClass ("JUCESystemTrayView_") + { + addIvar ("owner"); + addIvar ("image"); + + addMethod (@selector (mouseDown:), handleEventDown, "v@:@"); + addMethod (@selector (rightMouseDown:), handleEventDown, "v@:@"); + addMethod (@selector (drawRect:), drawRect, "v@:@"); + addMethod (@selector (frameChanged:), frameChanged, "v@:@"); + + registerClass(); + } + + static ViewBasedStatusItem* getOwner (id self) { return getIvar (self, "owner"); } + static NSImage* getImage (id self) { return getIvar (self, "image"); } + static void setOwner (id self, ViewBasedStatusItem* owner) { object_setInstanceVariable (self, "owner", owner); } + static void setImage (id self, NSImage* image) { object_setInstanceVariable (self, "image", image); } + + static void frameChanged (id self, SEL, NSNotification*) + { + if (auto* owner = getOwner (self)) + { + NSRect r = [[[owner->statusItem.get() view] window] frame]; + NSRect sr = [[[NSScreen screens] objectAtIndex: 0] frame]; + r.origin.y = sr.size.height - r.origin.y - r.size.height; + owner->owner.setBounds (convertToRectInt (r)); + } + } + + private: + static void handleEventDown (id self, SEL, NSEvent* e) + { + if (auto* owner = getOwner (self)) + owner->handleStatusItemAction (e); + } + + static void drawRect (id self, SEL, NSRect) + { + NSRect bounds = [self bounds]; + + if (auto* owner = getOwner (self)) + [owner->statusItem.get() drawStatusBarBackgroundInRect: bounds + withHighlight: owner->isHighlighted]; + + if (NSImage* const im = getImage (self)) + { + NSSize imageSize = [im size]; + + [im drawInRect: NSMakeRect (bounds.origin.x + ((bounds.size.width - imageSize.width) / 2.0f), + bounds.origin.y + ((bounds.size.height - imageSize.height) / 2.0f), + imageSize.width, imageSize.height) + fromRect: NSZeroRect + operation: NSCompositingOperationSourceOver + fraction: 1.0f]; + } + } + }; + + //============================================================================== + std::unique_ptr view; + bool isHighlighted = false; }; +//============================================================================== +class SystemTrayIconComponent::Pimpl +{ +public: + //============================================================================== + Pimpl (SystemTrayIconComponent& iconComp, const Image& im) + { + if (std::floor (NSFoundationVersionNumber) > NSFoundationVersionNumber10_10) + statusItemHolder = std::make_unique (iconComp, im); + else + statusItemHolder = std::make_unique (iconComp, im); + } + + //============================================================================== + std::unique_ptr statusItemHolder; + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Pimpl) +}; //============================================================================== void SystemTrayIconComponent::setIconImage (const Image&, const Image& templateImage) @@ -208,7 +399,7 @@ void SystemTrayIconComponent::setIconImage (const Image&, const Image& templateI if (pimpl == nullptr) pimpl.reset (new Pimpl (*this, templateImage)); else - pimpl->updateIcon (templateImage); + pimpl->statusItemHolder->updateIcon (templateImage); } else { @@ -221,10 +412,10 @@ void SystemTrayIconComponent::setIconTooltip (const String&) // xxx not yet implemented! } -void SystemTrayIconComponent::setHighlighted (bool highlight) +void SystemTrayIconComponent::setHighlighted (bool shouldHighlight) { if (pimpl != nullptr) - pimpl->setHighlighted (highlight); + pimpl->statusItemHolder->setHighlighted (shouldHighlight); } void SystemTrayIconComponent::showInfoBubble (const String& /*title*/, const String& /*content*/) @@ -239,13 +430,15 @@ void SystemTrayIconComponent::hideInfoBubble() void* SystemTrayIconComponent::getNativeHandle() const { - return pimpl != nullptr ? pimpl->getStatusItem() : nullptr; + return pimpl != nullptr ? pimpl->statusItemHolder->statusItem.get() : nullptr; } void SystemTrayIconComponent::showDropdownMenu (const PopupMenu& menu) { if (pimpl != nullptr) - pimpl->showMenu (menu); + pimpl->statusItemHolder->showMenu (menu); } +#pragma clang diagnostic pop + } // namespace juce diff --git a/modules/juce_gui_extra/native/juce_win32_WebBrowserComponent.cpp b/modules/juce_gui_extra/native/juce_win32_WebBrowserComponent.cpp index e9910736..afdc0b63 100644 --- a/modules/juce_gui_extra/native/juce_win32_WebBrowserComponent.cpp +++ b/modules/juce_gui_extra/native/juce_win32_WebBrowserComponent.cpp @@ -87,8 +87,6 @@ public: { if (browser != nullptr) { - LPSAFEARRAY sa = nullptr; - VARIANT headerFlags, frame, postDataVar, headersVar; // (_variant_t isn't available in all compilers) VariantInit (&headerFlags); VariantInit (&frame); @@ -103,7 +101,7 @@ public: if (postData != nullptr && postData->getSize() > 0) { - sa = SafeArrayCreateVector (VT_UI1, 0, (ULONG) postData->getSize()); + auto sa = SafeArrayCreateVector (VT_UI1, 0, (ULONG) postData->getSize()); if (sa != nullptr) { @@ -121,8 +119,13 @@ public: V_VT (&postDataVar2) = VT_ARRAY | VT_UI1; V_ARRAY (&postDataVar2) = sa; + sa = nullptr; postDataVar = postDataVar2; } + else + { + SafeArrayDestroy (sa); + } } } @@ -130,9 +133,6 @@ public: browser->Navigate (urlBSTR, &headerFlags, &frame, &postDataVar, &headersVar); SysFreeString (urlBSTR); - if (sa != nullptr) - SafeArrayDestroy (sa); - VariantClear (&headerFlags); VariantClear (&frame); VariantClear (&postDataVar); @@ -187,7 +187,7 @@ private: *pDispParams->rgvarg[0].pboolVal = VARIANT_FALSE; // IWebBrowser2 also reports http status codes here, we need - // report only network erros + // report only network errors if (statusCode < 0) { LPTSTR messageBuffer = nullptr; diff --git a/modules/juce_opengl/juce_opengl.h b/modules/juce_opengl/juce_opengl.h index 19f67c98..97e73b1f 100644 --- a/modules/juce_opengl/juce_opengl.h +++ b/modules/juce_opengl/juce_opengl.h @@ -24,6 +24,7 @@ ============================================================================== */ + /******************************************************************************* The block below describes the properties of this module, and is read by the Projucer to automatically generate project code that uses it. @@ -33,19 +34,19 @@ BEGIN_JUCE_MODULE_DECLARATION - ID: juce_opengl - vendor: juce - version: 5.4.5 - name: JUCE OpenGL classes - description: Classes for rendering OpenGL in a JUCE window. - website: http://www.juce.com/juce - license: GPL/Commercial - - dependencies: juce_gui_extra - OSXFrameworks: OpenGL - iOSFrameworks: OpenGLES - linuxLibs: GL - mingwLibs: opengl32 + ID: juce_opengl + vendor: juce + version: 5.4.6 + name: JUCE OpenGL classes + description: Classes for rendering OpenGL in a JUCE window. + website: http://www.juce.com/juce + license: GPL/Commercial + + dependencies: juce_gui_extra + OSXFrameworks: OpenGL + iOSFrameworks: OpenGLES + linuxLibs: GL + mingwLibs: opengl32 END_JUCE_MODULE_DECLARATION diff --git a/modules/juce_opengl/native/juce_OpenGL_ios.h b/modules/juce_opengl/native/juce_OpenGL_ios.h index 24a849b9..c4fb799c 100644 --- a/modules/juce_opengl/native/juce_OpenGL_ios.h +++ b/modules/juce_opengl/native/juce_OpenGL_ios.h @@ -89,7 +89,7 @@ public: if (context != nil) { // I'd prefer to put this stuff in the initialiseOnRenderThread() call, but doing - // so causes myserious timing-related failures. + // so causes mysterious timing-related failures. [EAGLContext setCurrentContext: context]; createGLBuffers(); deactivateCurrentContext(); diff --git a/modules/juce_opengl/opengl/juce_OpenGLContext.cpp b/modules/juce_opengl/opengl/juce_OpenGLContext.cpp index 9850c115..b6257456 100644 --- a/modules/juce_opengl/opengl/juce_OpenGLContext.cpp +++ b/modules/juce_opengl/opengl/juce_OpenGLContext.cpp @@ -105,7 +105,7 @@ public: if (renderThread != nullptr) { // make sure everything has finished executing - destroying.set (1); + destroying = true; if (workQueue.size() > 0) { @@ -142,6 +142,16 @@ public: renderThread->addJob (this, false); } + #if JUCE_MAC + static CVReturn displayLinkCallback (CVDisplayLinkRef, const CVTimeStamp*, const CVTimeStamp*, + CVOptionFlags, CVOptionFlags*, void* displayLinkContext) + { + auto* self = (CachedImage*) displayLinkContext; + self->renderFrame(); + return kCVReturnSuccess; + } + #endif + //============================================================================== void paint (Graphics&) override { @@ -214,7 +224,9 @@ public: bool renderFrame() { MessageManager::Lock::ScopedTryLockType mmLock (messageManagerLock, false); - const bool isUpdating = needsUpdate.compareAndSetBool (0, 1); + + auto isUpdatingTestValue = true; + auto isUpdating = needsUpdate.compare_exchange_strong (isUpdatingTestValue, false); if (context.renderComponents && isUpdating) { @@ -464,10 +476,14 @@ public: if (shouldExit()) break; + #if JUCE_MAC + repaintEvent.wait (1000); + #else if (! renderFrame()) repaintEvent.wait (5); // failed to render, so avoid a tight fail-loop. else if (! context.continuousRepaint && ! shouldExit()) repaintEvent.wait (-1); + #endif } hasInitialised = false; @@ -519,11 +535,22 @@ public: if (context.renderer != nullptr) context.renderer->newOpenGLContextCreated(); + #if JUCE_MAC + CVDisplayLinkCreateWithActiveCGDisplays (&displayLink); + CVDisplayLinkSetOutputCallback (displayLink, &displayLinkCallback, this); + CVDisplayLinkStart (displayLink); + #endif + return true; } void shutdownOnThread() { + #if JUCE_MAC + CVDisplayLinkStop (displayLink); + CVDisplayLinkRelease (displayLink); + #endif + if (context.renderer != nullptr) context.renderer->openGLContextClosing(); @@ -588,7 +615,7 @@ public: void execute (OpenGLContext::AsyncWorker::Ptr workerToUse, bool shouldBlock, bool calledFromDestructor = false) { - if (calledFromDestructor || destroying.get() == 0) + if (calledFromDestructor || ! destroying) { if (shouldBlock) { @@ -646,10 +673,12 @@ public: #else bool shadersAvailable = false; #endif - bool hasInitialised = false; - Atomic needsUpdate { 1 }, destroying; + std::atomic hasInitialised { false }, needsUpdate { true }, destroying { false }; uint32 lastMMLockReleaseTime = 0; + #if JUCE_MAC + CVDisplayLinkRef displayLink; + #endif std::unique_ptr renderThread; ReferenceCountedArray workQueue; MessageManager::Lock messageManagerLock; diff --git a/modules/juce_opengl/opengl/juce_OpenGLContext.h b/modules/juce_opengl/opengl/juce_OpenGLContext.h index a6871e80..c3fda19a 100644 --- a/modules/juce_opengl/opengl/juce_OpenGLContext.h +++ b/modules/juce_opengl/opengl/juce_OpenGLContext.h @@ -248,7 +248,7 @@ public: This function can only be called if the context is attached to a component. Otherwise, this function will assert. - This function is useful when you need to excute house-keeping tasks such + This function is useful when you need to execute house-keeping tasks such as allocating, deallocating textures or framebuffers. As such, the functor will execute without locking the message thread. Therefore, it is not intended for any drawing commands or GUI code. Any GUI code should be @@ -273,7 +273,7 @@ public: */ unsigned int getFrameBufferID() const noexcept; - /** Returns an OS-dependent handle to some kind of underlting OS-provided GL context. + /** Returns an OS-dependent handle to some kind of underlying OS-provided GL context. The exact type of the value returned will depend on the OS and may change if the implementation changes. If you want to use this, digging around in the diff --git a/modules/juce_osc/juce_osc.h b/modules/juce_osc/juce_osc.h index e4edc3d9..a6d75eae 100644 --- a/modules/juce_osc/juce_osc.h +++ b/modules/juce_osc/juce_osc.h @@ -24,6 +24,7 @@ ============================================================================== */ + /******************************************************************************* The block below describes the properties of this module, and is read by the Projucer to automatically generate project code that uses it. @@ -33,15 +34,15 @@ BEGIN_JUCE_MODULE_DECLARATION - ID: juce_osc - vendor: juce - version: 5.4.5 - name: JUCE OSC classes - description: Open Sound Control implementation. - website: http://www.juce.com/juce - license: GPL/Commercial + ID: juce_osc + vendor: juce + version: 5.4.6 + name: JUCE OSC classes + description: Open Sound Control implementation. + website: http://www.juce.com/juce + license: GPL/Commercial - dependencies: juce_core, juce_events + dependencies: juce_core, juce_events END_JUCE_MODULE_DECLARATION diff --git a/modules/juce_osc/osc/juce_OSCAddress.h b/modules/juce_osc/osc/juce_OSCAddress.h index 542bf938..e24f2d5e 100644 --- a/modules/juce_osc/osc/juce_OSCAddress.h +++ b/modules/juce_osc/osc/juce_OSCAddress.h @@ -130,7 +130,7 @@ public: bool matches (const OSCAddress& address) const noexcept; /** Checks whether the OSCAddressPattern contains any of the allowed OSC - address patttern wildcards: ?, *, [], {} + address pattern wildcards: ?, *, [], {} @returns true if the OSCAddressPattern contains OSC wildcards, false otherwise. */ diff --git a/modules/juce_osc/osc/juce_OSCTimeTag.h b/modules/juce_osc/osc/juce_OSCTimeTag.h index 29a5a037..a1e0d3b6 100644 --- a/modules/juce_osc/osc/juce_OSCTimeTag.h +++ b/modules/juce_osc/osc/juce_OSCTimeTag.h @@ -70,7 +70,7 @@ public: */ Time toTime() const noexcept; - /** Returns true if the OSCTimeTag object has the special value representing "immedately". */ + /** Returns true if the OSCTimeTag object has the special value representing "immediately". */ bool isImmediately() const noexcept; /** Returns the raw binary OSC time tag representation. */ diff --git a/modules/juce_product_unlocking/in_app_purchases/juce_InAppPurchases.cpp b/modules/juce_product_unlocking/in_app_purchases/juce_InAppPurchases.cpp index ca53510a..8609cd58 100644 --- a/modules/juce_product_unlocking/in_app_purchases/juce_InAppPurchases.cpp +++ b/modules/juce_product_unlocking/in_app_purchases/juce_InAppPurchases.cpp @@ -61,13 +61,11 @@ void InAppPurchases::getProductsInformation (const StringArray& productIdentifie } void InAppPurchases::purchaseProduct (const String& productIdentifier, - bool isSubscription, - const StringArray& upgradeProductIdentifiers, + const String& upgradeProductIdentifier, bool creditForUnusedSubscription) { #if JUCE_ANDROID || JUCE_IOS || JUCE_MAC - pimpl->purchaseProduct (productIdentifier, isSubscription, - upgradeProductIdentifiers, creditForUnusedSubscription); + pimpl->purchaseProduct (productIdentifier, upgradeProductIdentifier, creditForUnusedSubscription); #else Listener::PurchaseInfo purchaseInfo { Purchase { "", productIdentifier, {}, {}, {} }, {} }; diff --git a/modules/juce_product_unlocking/in_app_purchases/juce_InAppPurchases.h b/modules/juce_product_unlocking/in_app_purchases/juce_InAppPurchases.h index e2bd100c..38d21767 100644 --- a/modules/juce_product_unlocking/in_app_purchases/juce_InAppPurchases.h +++ b/modules/juce_product_unlocking/in_app_purchases/juce_InAppPurchases.h @@ -200,19 +200,15 @@ public: @param productIdentifier The product identifier. - @param isSubscription (Android only) defines if a product a user wants to buy is a subscription or a one-time purchase. - On iOS, type of the product is derived implicitly. - - @param upgradeOrDowngradeFromSubscriptionsWithProductIdentifiers (Android only) specifies subscriptions that will be replaced by the - one being purchased now. Used only when buying a subscription - that is an upgrade or downgrade from other ones. + @param upgradeOrDowngradeFromSubscriptionsWithProductIdentifier (Android only) specifies the subscription that will be replaced by + the one being purchased now. Used only when buying a subscription + that is an upgrade or downgrade from another. @param creditForUnusedSubscription (Android only) controls whether a user should be credited for any unused subscription time on - the products that are being upgraded or downgraded. + the product that is being upgraded or downgraded. */ void purchaseProduct (const String& productIdentifier, - bool isSubscription, - const StringArray& upgradeOrDowngradeFromSubscriptionsWithProductIdentifiers = {}, + const String& upgradeOrDowngradeFromSubscriptionWithProductIdentifier = {}, bool creditForUnusedSubscription = true); /** Asynchronously asks about a list of products that a user has already bought. Upon completion, Listener::purchasesListReceived() @@ -260,6 +256,22 @@ public: /** iOS only: Cancels downloads of hosted content from the store. */ void cancelDownloads (const Array& downloads); + //============================================================================== + // On Android, it is no longer necessary to specify whether the product being purchased is a subscription + // and only a single subscription can be upgraded/downgraded. Use the updated purchaseProduct() method + // which takes a single String argument. + JUCE_DEPRECATED_WITH_BODY (void purchaseProduct (const String& productIdentifier, + bool isSubscription, + const StringArray& upgradeOrDowngradeFromSubscriptionsWithProductIdentifiers = {}, + bool creditForUnusedSubscription = true), + { + + ignoreUnused (isSubscription); + purchaseProduct (productIdentifier, + upgradeOrDowngradeFromSubscriptionsWithProductIdentifiers[0], + creditForUnusedSubscription); + }) + private: //============================================================================== #ifndef DOXYGEN diff --git a/modules/juce_product_unlocking/juce_product_unlocking.h b/modules/juce_product_unlocking/juce_product_unlocking.h index 35033642..4cd5270b 100644 --- a/modules/juce_product_unlocking/juce_product_unlocking.h +++ b/modules/juce_product_unlocking/juce_product_unlocking.h @@ -24,6 +24,7 @@ ============================================================================== */ + /******************************************************************************* The block below describes the properties of this module, and is read by the Projucer to automatically generate project code that uses it. @@ -33,15 +34,15 @@ BEGIN_JUCE_MODULE_DECLARATION - ID: juce_product_unlocking - vendor: juce - version: 5.4.5 - name: JUCE Online marketplace support - description: Classes for online product authentication - website: http://www.juce.com/juce - license: GPL/Commercial + ID: juce_product_unlocking + vendor: juce + version: 5.4.6 + name: JUCE Online marketplace support + description: Classes for online product authentication + website: http://www.juce.com/juce + license: GPL/Commercial - dependencies: juce_cryptography juce_core + dependencies: juce_cryptography juce_core, juce_events END_JUCE_MODULE_DECLARATION @@ -68,6 +69,7 @@ //============================================================================== #include #include +#include #if JUCE_MODULE_AVAILABLE_juce_data_structures #include diff --git a/modules/juce_product_unlocking/marketplace/juce_OnlineUnlockForm.h b/modules/juce_product_unlocking/marketplace/juce_OnlineUnlockForm.h index b3b3d7c0..33a677f7 100644 --- a/modules/juce_product_unlocking/marketplace/juce_OnlineUnlockForm.h +++ b/modules/juce_product_unlocking/marketplace/juce_OnlineUnlockForm.h @@ -27,7 +27,7 @@ namespace juce { -/** Acts as a GUI which asks the user for their details, and calls the approriate +/** Acts as a GUI which asks the user for their details, and calls the appropriate methods on your OnlineUnlockStatus object to attempt to register the app. You should create one of these components and add it to your parent window, diff --git a/modules/juce_product_unlocking/native/javaopt/app/com/roli/juce/JuceBillingClient.java b/modules/juce_product_unlocking/native/javaopt/app/com/roli/juce/JuceBillingClient.java new file mode 100644 index 00000000..ad63f5ba --- /dev/null +++ b/modules/juce_product_unlocking/native/javaopt/app/com/roli/juce/JuceBillingClient.java @@ -0,0 +1,173 @@ +package com.roli.juce; + +import com.android.billingclient.api.*; + +public class JuceBillingClient implements PurchasesUpdatedListener { + private native void skuDetailsQueryCallback(long host, java.util.List skuDetails); + private native void purchasesListQueryCallback(long host, java.util.List purchases); + private native void purchaseCompletedCallback(long host, Purchase purchase, int responseCode); + private native void purchaseConsumedCallback(long host, String productIdentifier, int responseCode); + + public JuceBillingClient(android.content.Context context, long hostToUse) { + host = hostToUse; + + billingClient = BillingClient.newBuilder(context) + .enablePendingPurchases() + .setListener(this) + .build(); + + billingClient.startConnection(null); + } + + public void endConnection() { + billingClient.endConnection(); + } + + public boolean isReady() { + return billingClient.isReady(); + } + + public boolean isBillingSupported() { + return billingClient.isFeatureSupported(BillingClient.FeatureType.SUBSCRIPTIONS).getResponseCode() + == BillingClient.BillingResponseCode.OK; + } + + public void querySkuDetails(final String[] skusToQuery) { + executeOnBillingClientConnection(new Runnable() { + @Override + public void run() { + final java.util.List skuList = java.util.Arrays.asList(skusToQuery); + + SkuDetailsParams.Builder params = SkuDetailsParams.newBuilder() + .setSkusList(skuList) + .setType(BillingClient.SkuType.INAPP); + + billingClient.querySkuDetailsAsync(params.build(), new SkuDetailsResponseListener() { + @Override + public void onSkuDetailsResponse(BillingResult billingResult, final java.util.List inAppSkuDetails) { + if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK) { + SkuDetailsParams.Builder params = SkuDetailsParams.newBuilder() + .setSkusList(skuList) + .setType(BillingClient.SkuType.SUBS); + + billingClient.querySkuDetailsAsync(params.build(), new SkuDetailsResponseListener() { + @Override + public void onSkuDetailsResponse(BillingResult billingResult, java.util.List subsSkuDetails) { + if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK) { + subsSkuDetails.addAll(inAppSkuDetails); + skuDetailsQueryCallback(host, subsSkuDetails); + } + } + }); + } + } + }); + } + }); + } + + public void launchBillingFlow(final android.app.Activity activity, final BillingFlowParams params) { + executeOnBillingClientConnection(new Runnable() { + @Override + public void run() { + BillingResult r = billingClient.launchBillingFlow(activity, params); + } + }); + } + + public void queryPurchases() { + executeOnBillingClientConnection(new Runnable() { + @Override + public void run() { + Purchase.PurchasesResult inAppPurchases = billingClient.queryPurchases(BillingClient.SkuType.INAPP); + Purchase.PurchasesResult subsPurchases = billingClient.queryPurchases(BillingClient.SkuType.SUBS); + + if (inAppPurchases.getResponseCode() == BillingClient.BillingResponseCode.OK + && subsPurchases.getResponseCode() == BillingClient.BillingResponseCode.OK) { + java.util.List purchaseList = inAppPurchases.getPurchasesList(); + purchaseList.addAll(subsPurchases.getPurchasesList()); + + purchasesListQueryCallback(host, purchaseList); + return; + } + + purchasesListQueryCallback(host, null); + } + }); + } + + public void consumePurchase(final String productIdentifier, final String purchaseToken) { + executeOnBillingClientConnection(new Runnable() { + @Override + public void run() { + ConsumeParams consumeParams = ConsumeParams.newBuilder() + .setPurchaseToken(purchaseToken) + .build(); + + billingClient.consumeAsync(consumeParams, new ConsumeResponseListener() { + @Override + public void onConsumeResponse(BillingResult billingResult, String purchaseToken) { + purchaseConsumedCallback(host, productIdentifier, billingResult.getResponseCode()); + } + }); + } + }); + } + + @Override + public void onPurchasesUpdated(BillingResult result, java.util.List purchases) { + int responseCode = result.getResponseCode(); + + if (purchases != null) { + for (Purchase purchase : purchases) { + handlePurchase(purchase, responseCode); + } + } else { + purchaseCompletedCallback(host, null, responseCode); + } + } + + private void executeOnBillingClientConnection(Runnable runnable) { + if (billingClient.isReady()) { + runnable.run(); + } else { + connectAndExecute(runnable); + } + } + + private void connectAndExecute(final Runnable executeOnSuccess) { + billingClient.startConnection(new BillingClientStateListener() { + @Override + public void onBillingSetupFinished(BillingResult billingResponse) { + if (billingResponse.getResponseCode() == BillingClient.BillingResponseCode.OK) { + if (executeOnSuccess != null) { + executeOnSuccess.run(); + } + } + } + + @Override + public void onBillingServiceDisconnected() { + } + }); + } + + private void handlePurchase(final Purchase purchase, final int responseCode) { + purchaseCompletedCallback(host, purchase, responseCode); + + if (responseCode == BillingClient.BillingResponseCode.OK + && purchase.getPurchaseState() == Purchase.PurchaseState.PURCHASED + && !purchase.isAcknowledged()) { + executeOnBillingClientConnection(new Runnable() { + @Override + public void run() { + AcknowledgePurchaseParams acknowledgePurchaseParams = AcknowledgePurchaseParams.newBuilder().setPurchaseToken(purchase.getPurchaseToken()).build(); + billingClient.acknowledgePurchase(acknowledgePurchaseParams, null); + } + }); + } + } + + private long host = 0; + private BillingClient billingClient; +} diff --git a/modules/juce_product_unlocking/native/juce_android_InAppPurchases.cpp b/modules/juce_product_unlocking/native/juce_android_InAppPurchases.cpp index 9dbb5d03..9d2ee8ac 100644 --- a/modules/juce_product_unlocking/native/juce_android_InAppPurchases.cpp +++ b/modules/juce_product_unlocking/native/juce_android_InAppPurchases.cpp @@ -28,830 +28,495 @@ namespace juce { #define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \ - METHOD (isBillingSupported, "isBillingSupported", "(ILjava/lang/String;Ljava/lang/String;)I") \ - METHOD (getSkuDetails, "getSkuDetails", "(ILjava/lang/String;Ljava/lang/String;Landroid/os/Bundle;)Landroid/os/Bundle;") \ - METHOD (getBuyIntent, "getBuyIntent", "(ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Landroid/os/Bundle;") \ - METHOD (getBuyIntentExtraParams, "getBuyIntentExtraParams", "(ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Landroid/os/Bundle;)Landroid/os/Bundle;") \ - METHOD (getPurchases, "getPurchases", "(ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)Landroid/os/Bundle;") \ - METHOD (consumePurchase, "consumePurchase", "(ILjava/lang/String;Ljava/lang/String;)I") \ - METHOD (getPurchaseHistory, "getPurchaseHistory", "(ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;Landroid/os/Bundle;)Landroid/os/Bundle;") - -DECLARE_JNI_CLASS (IInAppBillingService, "com/android/vending/billing/IInAppBillingService") + METHOD (getSku, "getSku", "()Ljava/lang/String;") \ + METHOD (getTitle, "getTitle", "()Ljava/lang/String;") \ + METHOD (getDescription, "getDescription", "()Ljava/lang/String;") \ + METHOD (getPrice, "getPrice", "()Ljava/lang/String;") \ + METHOD (getPriceCurrencyCode, "getPriceCurrencyCode", "()Ljava/lang/String;") + +DECLARE_JNI_CLASS (SkuDetails, "com/android/billingclient/api/SkuDetails") #undef JNI_CLASS_MEMBERS #define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \ - STATICMETHOD (asInterface, "asInterface", "(Landroid/os/IBinder;)Lcom/android/vending/billing/IInAppBillingService;") \ + STATICMETHOD (newBuilder, "newBuilder", "()Lcom/android/billingclient/api/BillingFlowParams$Builder;") -DECLARE_JNI_CLASS (IInAppBillingServiceStub, "com/android/vending/billing/IInAppBillingService$Stub") +DECLARE_JNI_CLASS (BillingFlowParams, "com/android/billingclient/api/BillingFlowParams") #undef JNI_CLASS_MEMBERS -//============================================================================== -struct ServiceConnection : public AndroidInterfaceImplementer -{ - virtual void onServiceConnected (jobject component, jobject iBinder) = 0; - virtual void onServiceDisconnected (jobject component) = 0; - - jobject invoke (jobject proxy, jobject method, jobjectArray args) override - { - auto* env = getEnv(); - auto methodName = juceString ((jstring) env->CallObjectMethod (method, JavaMethod.getName)); +#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \ + METHOD (build, "build", "()Lcom/android/billingclient/api/BillingFlowParams;") \ + METHOD (setOldSku, "setOldSku", "(Ljava/lang/String;Ljava/lang/String;)Lcom/android/billingclient/api/BillingFlowParams$Builder;") \ + METHOD (setReplaceSkusProrationMode, "setReplaceSkusProrationMode", "(I)Lcom/android/billingclient/api/BillingFlowParams$Builder;") \ + METHOD (setSkuDetails, "setSkuDetails", "(Lcom/android/billingclient/api/SkuDetails;)Lcom/android/billingclient/api/BillingFlowParams$Builder;") - if (methodName == "onServiceConnected") - { - onServiceConnected (env->GetObjectArrayElement (args, 0), - env->GetObjectArrayElement (args, 1)); - return nullptr; - } +DECLARE_JNI_CLASS (BillingFlowParamsBuilder, "com/android/billingclient/api/BillingFlowParams$Builder") +#undef JNI_CLASS_MEMBERS - if (methodName == "onServiceDisconnected") - { - onServiceDisconnected (env->GetObjectArrayElement (args, 0)); - return nullptr; - } +#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \ + METHOD (getOrderId, "getOrderId", "()Ljava/lang/String;") \ + METHOD (getSku, "getSku", "()Ljava/lang/String;") \ + METHOD (getPackageName, "getPackageName", "()Ljava/lang/String;") \ + METHOD (getPurchaseTime, "getPurchaseTime", "()J") \ + METHOD (getPurchaseToken, "getPurchaseToken", "()Ljava/lang/String;") - return AndroidInterfaceImplementer::invoke (proxy, method, args); - } -}; +DECLARE_JNI_CLASS (AndroidPurchase, "com/android/billingclient/api/Purchase") +#undef JNI_CLASS_MEMBERS //============================================================================== -struct InAppPurchases::Pimpl : private AsyncUpdater, - private ServiceConnection +struct InAppPurchases::Pimpl { - Pimpl (InAppPurchases& parent) : owner (parent) + Pimpl (InAppPurchases& parent) + : owner (parent), + billingClient (LocalRef (getEnv()->NewObject (JuceBillingClient, + JuceBillingClient.constructor, + getAppContext().get(), + (jlong) this))) { - auto* env = getEnv(); - auto intent = env->NewObject (AndroidIntent, AndroidIntent.constructWithString, - javaString ("com.android.vending.billing.InAppBillingService.BIND").get()); - env->CallObjectMethod (intent, AndroidIntent.setPackage, javaString ("com.android.vending").get()); - - serviceConnection = GlobalRef (CreateJavaInterface (this, "android/content/ServiceConnection")); - - env->CallBooleanMethod (getCurrentActivity().get(), AndroidContext.bindService, intent, - serviceConnection.get(), 1 /*BIND_AUTO_CREATE*/); - - if (threadPool == nullptr) - threadPool.reset (new ThreadPool (1)); } ~Pimpl() { - threadPool = nullptr; - - if (serviceConnection != nullptr) - { - getEnv()->CallVoidMethod (getCurrentActivity().get(), AndroidContext.unbindService, serviceConnection.get()); - serviceConnection.clear(); - } + getEnv()->CallVoidMethod (billingClient, JuceBillingClient.endConnection); } //============================================================================== - bool isInAppPurchasesSupported() { return isInAppPurchasesSupported (inAppBillingService); } + bool isInAppPurchasesSupported() const + { + return isReady() && getEnv()->CallBooleanMethod (billingClient, JuceBillingClient.isBillingSupported); + } void getProductsInformation (const StringArray& productIdentifiers) { - auto callback = [this](const Array& products) + skuDetailsQueryCallbackQueue.emplace ([this] (LocalRef skuDetailsList) { - const ScopedLock lock (getProductsInformationJobResultsLock); - getProductsInformationJobResults.insert (0, products); - triggerAsyncUpdate(); - }; + if (skuDetailsList != nullptr) + { + auto* env = getEnv(); + Array products; + + for (int i = 0; i < env->CallIntMethod (skuDetailsList, JavaList.size); ++i) + products.add (buildProduct (LocalRef (env->CallObjectMethod (skuDetailsList, JavaList.get, i)))); + + owner.listeners.call ([&] (Listener& l) { l.productsInfoReturned (products); }); + } + }); - threadPool->addJob (new GetProductsInformationJob (*this, getPackageName(), - productIdentifiers, callback), true); + querySkuDetailsAsync (convertToLowerCase (productIdentifiers)); } - void purchaseProduct (const String& productIdentifier, bool isSubscription, - const StringArray& subscriptionIdentifiers, bool creditForUnusedSubscription) + void purchaseProduct (const String& productIdentifier, + const String& subscriptionIdentifier, + bool creditForUnusedSubscription) { - // Upgrading/downgrading only makes sense for subscriptions! - jassert (subscriptionIdentifiers.isEmpty() || isSubscription); + skuDetailsQueryCallbackQueue.emplace ([=] (LocalRef skuDetailsList) + { + if (skuDetailsList != nullptr) + { + auto* env = getEnv(); - auto buyIntentBundle = getBuyIntentBundle (productIdentifier, isSubscription, - subscriptionIdentifiers, creditForUnusedSubscription); - auto* env = getEnv(); + if (env->CallIntMethod (skuDetailsList, JavaList.size) > 0) + { + LocalRef skuDetails (env->CallObjectMethod (skuDetailsList, JavaList.get, 0)); - auto responseCodeString = javaString ("RESPONSE_CODE"); - auto responseCode = env->CallIntMethod (buyIntentBundle.get(), AndroidBundle.getInt, responseCodeString.get()); + if (subscriptionIdentifier.isNotEmpty()) + changeExistingSubscription (skuDetails, subscriptionIdentifier, creditForUnusedSubscription); + else + purchaseProductWithSkuDetails (skuDetails); + } + } + }); - if (responseCode == 0) - { - auto buyIntentString = javaString ("BUY_INTENT"); - auto pendingIntent = LocalRef (env->CallObjectMethod (buyIntentBundle.get(), AndroidBundle.getParcelable, buyIntentString.get())); - - auto requestCode = 1001; - auto intentSender = LocalRef (env->CallObjectMethod (pendingIntent.get(), AndroidPendingIntent.getIntentSender)); - auto fillInIntent = LocalRef (env->NewObject (AndroidIntent, AndroidIntent.constructor)); - auto flagsMask = LocalRef (env->CallStaticObjectMethod (JavaInteger, JavaInteger.valueOf, 0)); - auto flagsValues = LocalRef (env->CallStaticObjectMethod (JavaInteger, JavaInteger.valueOf, 0)); - auto extraFlags = LocalRef (env->CallStaticObjectMethod (JavaInteger, JavaInteger.valueOf, 0)); - - env->CallVoidMethod (getCurrentActivity().get(), AndroidActivity.startIntentSenderForResult, intentSender.get(), requestCode, - fillInIntent.get(), flagsMask.get(), flagsValues.get(), extraFlags.get()); - } - else if (responseCode == 7) - { - // Item already bought. - notifyAboutPurchaseResult ({ {}, productIdentifier, juceString (getPackageName()), {}, {} }, true, statusCodeToUserString (responseCode)); - } + querySkuDetailsAsync (convertToLowerCase ({ productIdentifier })); } void restoreProductsBoughtList (bool, const juce::String&) { - auto callback = [this](const GetProductsBoughtJob::Result& r) + purchasesListQueryCallbackQueue.emplace ([this] (LocalRef purchasesList) { - const ScopedLock lock (getProductsBoughtJobResultsLock); - getProductsBoughtJobResults.insert (0, r); - triggerAsyncUpdate(); - }; + if (purchasesList != nullptr) + { + auto* env = getEnv(); + Array purchases; + + for (int i = 0; i < env->CallIntMethod (purchasesList, JavaArrayList.size); ++i) + { + LocalRef purchase (env->CallObjectMethod (purchasesList, JavaArrayList.get, i)); + purchases.add ({ buildPurchase (purchase), {} }); + } + + owner.listeners.call ([&] (Listener& l) { l.purchasesListRestored (purchases, true, NEEDS_TRANS ("Success")); }); + } + else + { + owner.listeners.call ([&] (Listener& l) { l.purchasesListRestored ({}, false, NEEDS_TRANS ("Failure")); }); + } + }); - threadPool->addJob (new GetProductsBoughtJob (*this, - getPackageName(), callback), true); + getProductsBoughtAsync(); } void consumePurchase (const String& productIdentifier, const String& purchaseToken) { - auto callback = [this](const ConsumePurchaseJob::Result& r) + if (purchaseToken.isEmpty()) { - const ScopedLock lock (consumePurchaseJobResultsLock); - consumePurchaseJobResults.insert (0, r); - triggerAsyncUpdate(); - }; + skuDetailsQueryCallbackQueue.emplace ([=] (LocalRef skuDetailsList) + { + if (skuDetailsList != nullptr) + { + auto* env = getEnv(); + + if (env->CallIntMethod (skuDetailsList, JavaList.size) > 0) + { + LocalRef sku (env->CallObjectMethod (skuDetailsList, JavaList.get, 0)); + + auto token = juceString (LocalRef ((jstring) env->CallObjectMethod (sku, AndroidPurchase.getSku))); + + if (token.isNotEmpty()) + { + consumePurchaseWithToken (productIdentifier, token); + return; + } + } + } + + notifyListenersAboutConsume (productIdentifier, false, NEEDS_TRANS ("Item unavailable")); + }); + + querySkuDetailsAsync (convertToLowerCase ({ productIdentifier })); + } - threadPool->addJob (new ConsumePurchaseJob (*this, getPackageName(), productIdentifier, - purchaseToken, callback), true); + consumePurchaseWithToken (productIdentifier, purchaseToken); } //============================================================================== - void startDownloads (const Array& downloads) + void startDownloads (const Array& downloads) { // Not available on this platform. ignoreUnused (downloads); jassertfalse; } - void pauseDownloads (const Array& downloads) + void pauseDownloads (const Array& downloads) { // Not available on this platform. ignoreUnused (downloads); jassertfalse; } - void resumeDownloads (const Array& downloads) + void resumeDownloads (const Array& downloads) { // Not available on this platform. ignoreUnused (downloads); jassertfalse; } - void cancelDownloads (const Array& downloads) + void cancelDownloads (const Array& downloads) { // Not available on this platform. ignoreUnused (downloads); jassertfalse; } - //============================================================================== - LocalRef getBuyIntentBundle (const String& productIdentifier, bool isSubscription, - const StringArray& subscriptionIdentifiers, bool creditForUnusedSubscription) +private: + #define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \ + METHOD (constructor, "", "(Landroid/content/Context;J)V") \ + METHOD (endConnection, "endConnection", "()V") \ + METHOD (isReady, "isReady", "()Z") \ + METHOD (isBillingSupported, "isBillingSupported", "()Z") \ + METHOD (querySkuDetails, "querySkuDetails", "([Ljava/lang/String;)V") \ + METHOD (launchBillingFlow, "launchBillingFlow", "(Landroid/app/Activity;Lcom/android/billingclient/api/BillingFlowParams;)V") \ + METHOD (queryPurchases, "queryPurchases", "()V") \ + METHOD (consumePurchase, "consumePurchase", "(Ljava/lang/String;Ljava/lang/String;)V") \ + \ + CALLBACK (skuDetailsQueryCallback, "skuDetailsQueryCallback", "(JLjava/util/List;)V") \ + CALLBACK (purchasesListQueryCallback, "purchasesListQueryCallback", "(JLjava/util/List;)V") \ + CALLBACK (purchaseCompletedCallback, "purchaseCompletedCallback", "(JLcom/android/billingclient/api/Purchase;I)V") \ + CALLBACK (purchaseConsumedCallback, "purchaseConsumedCallback", "(JLjava/lang/String;I)V") + + DECLARE_JNI_CLASS (JuceBillingClient, "com/roli/juce/JuceBillingClient") + #undef JNI_CLASS_MEMBERS + + static void JNICALL skuDetailsQueryCallback (JNIEnv*, jobject, jlong host, jobject skuDetailsList) { - auto* env = getEnv(); - - auto skuString = javaString (productIdentifier); - auto productTypeString = javaString (isSubscription ? "subs" : "inapp"); - auto devString = javaString (""); - - if (subscriptionIdentifiers.isEmpty()) - return LocalRef (inAppBillingService.callObjectMethod (IInAppBillingService.getBuyIntent, 3, - getPackageName().get(), skuString.get(), - productTypeString.get(), devString.get())); - - auto skuList = LocalRef (env->NewObject (JavaArrayList, JavaArrayList.constructor, - (int) subscriptionIdentifiers.size())); - - if (skuList.get() == 0) - { - jassertfalse; - return LocalRef (0); - } - - for (const auto& identifier : subscriptionIdentifiers) - env->CallBooleanMethod (skuList.get(), JavaArrayList.add, javaString (identifier).get()); - - auto extraParams = LocalRef (env->NewObject (AndroidBundle, AndroidBundle.constructor)); - - if (extraParams.get() == 0) - { - jassertfalse; - return LocalRef (0); - } - - auto skusToReplaceString = javaString ("skusToReplace"); - auto replaceSkusProrationString = javaString ("replaceSkusProration"); + if (auto* myself = reinterpret_cast (host)) + myself->updateSkuDetails (skuDetailsList); + } - env->CallVoidMethod (extraParams.get(), AndroidBundle.putStringArrayList, skusToReplaceString.get(), skuList.get()); - env->CallVoidMethod (extraParams.get(), AndroidBundle.putBoolean, replaceSkusProrationString.get(), creditForUnusedSubscription); + static void JNICALL purchasesListQueryCallback (JNIEnv*, jobject, jlong host, jobject purchasesList) + { + if (auto* myself = reinterpret_cast (host)) + myself->updatePurchasesList (purchasesList); + } - return LocalRef (inAppBillingService.callObjectMethod (IInAppBillingService.getBuyIntentExtraParams, 6, - getPackageName().get(), skuString.get(), - productTypeString.get(), devString.get(), - extraParams.get())); + static void JNICALL purchaseCompletedCallback (JNIEnv*, jobject, jlong host, jobject purchase, int responseCode) + { + if (auto* myself = reinterpret_cast (host)) + myself->purchaseCompleted (purchase, responseCode); } - //============================================================================== - void notifyAboutPurchaseResult (const InAppPurchases::Purchase& purchase, bool success, const String& statusDescription) + static void JNICALL purchaseConsumedCallback (JNIEnv*, jobject, jlong host, jstring productIdentifier, int responseCode) { - owner.listeners.call ([&] (Listener& l) { l.productPurchaseFinished ({ purchase, {} }, success, statusDescription); }); + if (auto* myself = reinterpret_cast (host)) + myself->purchaseConsumed (productIdentifier, responseCode); } //============================================================================== - bool checkIsReady() + bool isReady() const { - // It may take a few seconds for the in-app purchase service to connect - for (auto retries = 0; retries < 10 && inAppBillingService.get() == 0; ++retries) - Thread::sleep (500); - - return (inAppBillingService.get() != 0); + return getEnv()->CallBooleanMethod (billingClient, JuceBillingClient.isReady); } - static bool isInAppPurchasesSupported (jobject iapService) + bool checkIsReady() const { - if (iapService != nullptr) + for (int i = 0; i < 10; ++i) { - auto* env = getEnv(); - - auto inAppString = javaString ("inapp"); - auto subsString = javaString ("subs"); - - if (env->CallIntMethod (iapService, IInAppBillingService.isBillingSupported, 3, - getPackageName().get(), inAppString.get()) != 0) - return false; + if (isReady()) + return true; - if (env->CallIntMethod (iapService, IInAppBillingService.isBillingSupported, 3, - getPackageName().get(), subsString.get()) != 0) - return false; - - return true; + Thread::sleep (500); } - // Connecting to the in-app purchase server failed! This could have multiple reasons: - // 1) Your phone/emulator must support the google play store - // 2) Your phone must be logged into the google play store and be able to receive updates - // 3) It can take a few seconds after instantiation of the InAppPurchase class for - // in-app purchases to be avaialable on Android. return false; } //============================================================================== - void onServiceConnected (jobject, jobject iBinder) override + static StringArray convertToLowerCase (const StringArray& stringsToConvert) { - auto* env = getEnv(); - - LocalRef iapService (env->CallStaticObjectMethod (IInAppBillingServiceStub, - IInAppBillingServiceStub.asInterface, - iBinder)); + StringArray lowerCase; - if (isInAppPurchasesSupported (iapService)) - inAppBillingService = GlobalRef (iapService); + for (auto& s : stringsToConvert) + lowerCase.add (s.toLowerCase()); - // If you hit this assert, then in-app purchases is not available on your device, - // most likely due to too old version of Google Play API (hint: update Google Play on the device). - jassert (isInAppPurchasesSupported()); + return lowerCase; } - void onServiceDisconnected (jobject) override - { - inAppBillingService.clear(); - } - - //============================================================================== - static LocalRef getPackageName() + void querySkuDetailsAsync (const StringArray& productIdentifiers) { - return LocalRef ((jstring) (getEnv()->CallObjectMethod (getAppContext().get(), AndroidContext.getPackageName))); - } - - //============================================================================== - struct GetProductsInformationJob : public ThreadPoolJob - { - using Callback = std::function&)>; - - GetProductsInformationJob (Pimpl& parent, - const LocalRef& packageNameToUse, - const StringArray& productIdentifiersToUse, - const Callback& callbackToUse) - : ThreadPoolJob ("GetProductsInformationJob"), - owner (parent), - packageName (LocalRef (getEnv()->NewLocalRef (packageNameToUse.get()))), - productIdentifiers (productIdentifiersToUse), - callback (callbackToUse) - {} - - ThreadPoolJob::JobStatus runJob() override + Thread::launch ([=] { - jassert (callback); - - if (owner.checkIsReady()) - { - // Google's Billing API limitation - auto maxQuerySize = 20; - auto pi = 0; - - Array results; - StringArray identifiersToUse; - - for (auto i = 0; i < productIdentifiers.size(); ++i) - { - identifiersToUse.add (productIdentifiers[i].toLowerCase()); - ++pi; + if (! checkIsReady()) + return; - if (pi == maxQuerySize || i == productIdentifiers.size() - 1) - { - auto inAppProducts = processRetrievedProducts (queryProductsInformationFromService (identifiersToUse, "inapp")); - auto subsProducts = processRetrievedProducts (queryProductsInformationFromService (identifiersToUse, "subs")); - - results.addArray (inAppProducts); - results.addArray (subsProducts); - identifiersToUse.clear(); - pi = 0; - } - } - - if (callback) - callback (results); - } - else + MessageManager::callAsync ([=] { - if (callback) - callback ({}); - } - - return jobHasFinished; - } - - private: - LocalRef queryProductsInformationFromService (const StringArray& productIdentifiersToQuery, const String& productType) - { - auto* env = getEnv(); - - auto skuList = LocalRef (env->NewObject (JavaArrayList, JavaArrayList.constructor, productIdentifiersToQuery.size())); - - if (skuList.get() == 0) - return LocalRef (0); - - for (const auto& pi : productIdentifiersToQuery) - env->CallBooleanMethod (skuList.get(), JavaArrayList.add, javaString (pi).get()); - - auto querySkus = LocalRef (env->NewObject (AndroidBundle, AndroidBundle.constructor)); - - if (querySkus.get() == 0) - return LocalRef (0); - - auto itemIdListString = javaString ("ITEM_ID_LIST"); - - env->CallVoidMethod (querySkus.get(), AndroidBundle.putStringArrayList, itemIdListString.get(), skuList.get()); - - auto productTypeString = javaString (productType); - - auto productDetails = LocalRef (owner.inAppBillingService.callObjectMethod (IInAppBillingService.getSkuDetails, - 3, (jstring) packageName.get(), - productTypeString.get(), querySkus.get())); - - return productDetails; - } + getEnv()->CallVoidMethod (billingClient, + JuceBillingClient.querySkuDetails, + juceStringArrayToJava (productIdentifiers).get()); + }); + }); + } - Array processRetrievedProducts (LocalRef retrievedProducts) + void getProductsBoughtAsync() + { + Thread::launch ([=] { - Array products; + if (! checkIsReady()) + return; - if (owner.checkIsReady()) + MessageManager::callAsync ([=] { - auto* env = getEnv(); - - auto responseCodeString = javaString ("RESPONSE_CODE"); - - auto responseCode = env->CallIntMethod (retrievedProducts.get(), AndroidBundle.getInt, responseCodeString.get()); - - if (responseCode == 0) - { - auto detailsListString = javaString ("DETAILS_LIST"); - - auto responseList = LocalRef (env->CallObjectMethod (retrievedProducts.get(), AndroidBundle.getStringArrayList, - detailsListString.get())); - - if (responseList != 0) - { - auto iterator = LocalRef (env->CallObjectMethod (responseList.get(), JavaArrayList.iterator)); - - if (iterator.get() != 0) - { - for (;;) - { - if (! env->CallBooleanMethod (iterator, JavaIterator.hasNext)) - break; - - auto response = juce::LocalRef ((jstring)env->CallObjectMethod (iterator, JavaIterator.next)); - - if (response.get() != 0) - { - var responseData = JSON::parse (juceString (response.get())); - - if (DynamicObject* object = responseData.getDynamicObject()) - { - NamedValueSet& props = object->getProperties(); - - static Identifier productIdIdentifier ("productId"); - static Identifier titleIdentifier ("title"); - static Identifier descriptionIdentifier ("description"); - static Identifier priceIdentifier ("price"); - static Identifier priceCurrencyCodeIdentifier ("price_currency_code"); - - var productId = props[productIdIdentifier]; - var title = props[titleIdentifier]; - var description = props[descriptionIdentifier]; - var price = props[priceIdentifier]; - var priceCurrencyCode = props[priceCurrencyCodeIdentifier]; - - products.add ( { productId.toString(), - title.toString(), - description.toString(), - price.toString(), - priceCurrencyCode.toString() } ); - } - - } - } - } - } - } - } - - return products; - } - - Pimpl& owner; - GlobalRef packageName; - const StringArray productIdentifiers; - Callback callback; - }; + getEnv()->CallVoidMethod (billingClient, + JuceBillingClient.queryPurchases); + }); + }); + } //============================================================================== - struct GetProductsBoughtJob : public ThreadPoolJob + void notifyListenersAboutPurchase (const InAppPurchases::Purchase& purchase, bool success, const String& statusDescription) { - struct Result - { - bool success = false; - Array purchases; - String statusDescription; - }; - - using Callback = std::function; - - GetProductsBoughtJob (Pimpl& parent, - const LocalRef& packageNameToUse, - const Callback& callbackToUse) - : ThreadPoolJob ("GetProductsBoughtJob"), - owner (parent), - packageName (LocalRef (getEnv()->NewLocalRef (packageNameToUse.get()))), - callback (callbackToUse) - {} - - ThreadPoolJob::JobStatus runJob() override - { - jassert (callback); - - if (owner.checkIsReady()) - { - auto inAppPurchases = getProductsBought ("inapp", 0); - auto subsPurchases = getProductsBought ("subs", 0); - - inAppPurchases.addArray (subsPurchases); - - Array purchases; - - for (const auto& purchase : inAppPurchases) - purchases.add ({ purchase, {} }); - - if (callback) - callback ({true, purchases, "Success"}); - } - else - { - if (callback) - callback ({false, {}, "In-App purchases unavailable"}); - } - - return jobHasFinished; - } - - private: - Array getProductsBought (const String& productType, jstring continuationToken) - { - Array purchases; - auto* env = getEnv(); - - auto productTypeString = javaString (productType); - auto ownedItems = LocalRef (owner.inAppBillingService.callObjectMethod (IInAppBillingService.getPurchases, 3, - (jstring) packageName.get(), productTypeString.get(), - continuationToken)); - - if (ownedItems.get() != 0) - { - auto responseCodeString = javaString ("RESPONSE_CODE"); - auto responseCode = env->CallIntMethod (ownedItems.get(), AndroidBundle.getInt, responseCodeString.get()); - - if (responseCode == 0) - { - auto itemListString = javaString ("INAPP_PURCHASE_ITEM_LIST"); - auto dataListString = javaString ("INAPP_PURCHASE_DATA_LIST"); - auto signatureListString = javaString ("INAPP_DATA_SIGNATURE_LIST"); - auto continuationTokenString = javaString ("INAPP_CONTINUATION_TOKEN"); + owner.listeners.call ([&] (Listener& l) { l.productPurchaseFinished ({ purchase, {} }, success, statusDescription); }); + } - auto ownedSkus = LocalRef (env->CallObjectMethod (ownedItems.get(), AndroidBundle.getStringArrayList, itemListString.get())); - auto purchaseDataList = LocalRef (env->CallObjectMethod (ownedItems.get(), AndroidBundle.getStringArrayList, dataListString.get())); - auto signatureList = LocalRef (env->CallObjectMethod (ownedItems.get(), AndroidBundle.getStringArrayList, signatureListString.get())); - auto newContinuationToken = LocalRef ((jstring) env->CallObjectMethod (ownedItems.get(), AndroidBundle.getString, continuationTokenString.get())); + void notifyListenersAboutConsume (const String& productIdentifier, bool success, const String& statusDescription) + { + owner.listeners.call ([&] (Listener& l) { l.productConsumed (productIdentifier, success, statusDescription); }); + } - for (auto i = 0; i < env->CallIntMethod (purchaseDataList.get(), JavaArrayList.size); ++i) - { - auto sku = juceString ((jstring) (env->CallObjectMethod (ownedSkus.get(), JavaArrayList.get, i))); - auto purchaseData = juceString ((jstring) (env->CallObjectMethod (purchaseDataList.get(), JavaArrayList.get, i))); - auto signature = juceString ((jstring) (env->CallObjectMethod (signatureList.get(), JavaArrayList.get, i))); + LocalRef createBillingFlowParamsBuilder (LocalRef skuDetails) + { + auto* env = getEnv(); - var responseData = JSON::parse (purchaseData); + auto builder = LocalRef (env->CallStaticObjectMethod (BillingFlowParams, BillingFlowParams.newBuilder)); - if (auto* object = responseData.getDynamicObject()) - { - auto& props = object->getProperties(); - - static const Identifier orderIdIdentifier ("orderId"), - packageNameIdentifier ("packageName"), - productIdIdentifier ("productId"), - purchaseTimeIdentifier ("purchaseTime"), - purchaseTokenIdentifier ("purchaseToken"); - - var orderId = props[orderIdIdentifier]; - var appPackageName = props[packageNameIdentifier]; - var productId = props[productIdIdentifier]; - var purchaseTime = props[purchaseTimeIdentifier]; - var purchaseToken = props[purchaseTokenIdentifier]; - - String purchaseTimeString = Time (purchaseTime.toString().getLargeIntValue()).toString (true, true, true, true); - purchases.add ({ orderId.toString(), productId.toString(), appPackageName.toString(), purchaseTimeString, purchaseToken.toString() }); - } - } + return LocalRef (env->CallObjectMethod (builder.get(), + BillingFlowParamsBuilder.setSkuDetails, + skuDetails.get())); + } - if (newContinuationToken.get() != 0) - getProductsBought (productType, newContinuationToken.get()); - } - } + void launchBillingFlowWithParameters (LocalRef params) + { + LocalRef activity (getCurrentActivity()); - return purchases; - } + if (activity == nullptr) + activity = getMainActivity(); - Pimpl& owner; - GlobalRef packageName; - Callback callback; - }; + getEnv()->CallVoidMethod (billingClient, + JuceBillingClient.launchBillingFlow, + activity.get(), + params.get()); + } - //============================================================================== - class ConsumePurchaseJob : public ThreadPoolJob + void changeExistingSubscription (LocalRef skuDetails, const String& subscriptionIdentifier, bool creditForUnusedSubscription) { - public: - struct Result - { - bool success = false; - String productIdentifier; - String statusDescription; - }; - - using Callback = std::function; - - ConsumePurchaseJob (Pimpl& parent, - const LocalRef& packageNameToUse, - const String& productIdentifierToUse, - const String& purchaseTokenToUse, - const Callback& callbackToUse) - : ThreadPoolJob ("ConsumePurchaseJob"), - owner (parent), - packageName (LocalRef (getEnv()->NewLocalRef (packageNameToUse.get()))), - productIdentifier (productIdentifierToUse), - purchaseToken (purchaseTokenToUse), - callback (callbackToUse) - {} - - ThreadPoolJob::JobStatus runJob() override + if (! isReady()) { - jassert (callback); - - if (owner.checkIsReady()) - { - auto token = (! purchaseToken.isEmpty() ? purchaseToken : getPurchaseTokenForProductId (productIdentifier, false, 0)); - - if (token.isEmpty()) - { - if (callback) - callback ({ false, productIdentifier, NEEDS_TRANS ("Item not owned") }); - - return jobHasFinished; - } - - auto responseCode = owner.inAppBillingService.callIntMethod (IInAppBillingService.consumePurchase, 3, - (jstring)packageName.get(), javaString (token).get()); - - if (callback) - callback ({ responseCode == 0, productIdentifier, statusCodeToUserString (responseCode) }); - } - else - { - if (callback) - callback ({false, {}, "In-App purchases unavailable"}); - } - - return jobHasFinished; + notifyListenersAboutPurchase ({}, false, NEEDS_TRANS ("In-App purchases unavailable")); + return; } - private: - String getPurchaseTokenForProductId (const String productIdToLookFor, bool isSubscription, jstring continuationToken) + purchasesListQueryCallbackQueue.emplace ([=] (LocalRef purchasesList) { - auto productTypeString = javaString (isSubscription ? "subs" : "inapp"); - auto ownedItems = LocalRef (owner.inAppBillingService.callObjectMethod (IInAppBillingService.getPurchases, 3, - (jstring) packageName.get(), productTypeString.get(), - continuationToken)); - - if (ownedItems.get() != 0) + if (purchasesList != nullptr) { auto* env = getEnv(); - auto responseCodeString = javaString ("RESPONSE_CODE"); - auto responseCode = env->CallIntMethod (ownedItems.get(), AndroidBundle.getInt, responseCodeString.get()); - - if (responseCode == 0) + for (int i = 0; i < env->CallIntMethod (purchasesList, JavaArrayList.size); ++i) { - auto dataListString = javaString ("INAPP_PURCHASE_DATA_LIST"); - auto continuationTokenString = javaString ("INAPP_CONTINUATION_TOKEN"); + auto purchase = buildPurchase (LocalRef (env->CallObjectMethod (purchasesList.get(), JavaArrayList.get, i))); - auto purchaseDataList = LocalRef (env->CallObjectMethod (ownedItems.get(), AndroidBundle.getStringArrayList, dataListString.get())); - auto newContinuationToken = LocalRef ((jstring) env->CallObjectMethod (ownedItems.get(), AndroidBundle.getString, continuationTokenString.get())); - - for (auto i = 0; i < env->CallIntMethod (purchaseDataList.get(), JavaArrayList.size); ++i) + if (purchase.productId == subscriptionIdentifier) { - auto purchaseData = juceString ((jstring) (env->CallObjectMethod (purchaseDataList.get(), JavaArrayList.get, i))); - - var responseData = JSON::parse (purchaseData); + auto builder = createBillingFlowParamsBuilder (skuDetails); - if (auto* object = responseData.getDynamicObject()) - { - static const Identifier productIdIdentifier ("productId"), - purchaseTokenIdentifier ("purchaseToken"); + builder = LocalRef (env->CallObjectMethod (builder.get(), + BillingFlowParamsBuilder.setOldSku, + javaString (subscriptionIdentifier).get(), + javaString (purchase.purchaseToken).get())); - auto& props = object->getProperties(); - var productId = props[productIdIdentifier]; + if (! creditForUnusedSubscription) + builder = LocalRef (env->CallObjectMethod (builder.get(), + BillingFlowParamsBuilder.setReplaceSkusProrationMode, + 3 /*IMMEDIATE_WITHOUT_PRORATION*/)); - if (productId.toString() == productIdToLookFor) - return props[purchaseTokenIdentifier].toString(); - } + launchBillingFlowWithParameters (LocalRef (env->CallObjectMethod (builder.get(), + BillingFlowParamsBuilder.build))); } - - if (newContinuationToken.get() != 0) - return getPurchaseTokenForProductId (productIdToLookFor, isSubscription, newContinuationToken.get()); } } - return {}; - } + notifyListenersAboutPurchase ({}, false, NEEDS_TRANS ("Unable to get subscription details")); + }); - Pimpl& owner; - GlobalRef packageName; - const String productIdentifier, purchaseToken; - Callback callback; - }; + getProductsBoughtAsync(); + } - //============================================================================== - void handleAsyncUpdate() override + void purchaseProductWithSkuDetails (LocalRef skuDetails) { + if (! isReady()) { - const ScopedLock lock (getProductsInformationJobResultsLock); - - for (int i = getProductsInformationJobResults.size(); --i >= 0;) - { - const auto& result = getProductsInformationJobResults.getReference (i); - - owner.listeners.call ([&] (Listener& l) { l.productsInfoReturned (result); }); - getProductsInformationJobResults.remove (i); - } + notifyListenersAboutPurchase ({}, false, NEEDS_TRANS ("In-App purchases unavailable")); + return; } - { - const ScopedLock lock (getProductsBoughtJobResultsLock); - - for (int i = getProductsBoughtJobResults.size(); --i >= 0;) - { - const auto& result = getProductsBoughtJobResults.getReference (i); - - owner.listeners.call ([&] (Listener& l) { l.purchasesListRestored (result.purchases, result.success, result.statusDescription); }); - getProductsBoughtJobResults.remove (i); - } - } + launchBillingFlowWithParameters (LocalRef (getEnv()->CallObjectMethod (createBillingFlowParamsBuilder (skuDetails).get(), + BillingFlowParamsBuilder.build))); + } + void consumePurchaseWithToken (const String& productIdentifier, const String& purchaseToken) + { + if (! isReady()) { - const ScopedLock lock (consumePurchaseJobResultsLock); - - for (int i = consumePurchaseJobResults.size(); --i >= 0;) - { - const auto& result = consumePurchaseJobResults.getReference (i); - - owner.listeners.call ([&] (Listener& l) { l.productConsumed (result.productIdentifier, result.success, result.statusDescription); }); - consumePurchaseJobResults.remove (i); - } + notifyListenersAboutConsume (productIdentifier, false, NEEDS_TRANS ("In-App purchases unavailable")); + return; } + + getEnv()->CallObjectMethod (billingClient, + JuceBillingClient.consumePurchase, + LocalRef (javaString (productIdentifier)).get(), + LocalRef (javaString (purchaseToken)).get()); } //============================================================================== - void inAppPurchaseCompleted (jobject intentData) + static InAppPurchases::Purchase buildPurchase (LocalRef purchase) { + if (purchase == nullptr) + return {}; + auto* env = getEnv(); - auto inAppPurchaseDataString = javaString ("INAPP_PURCHASE_DATA"); - auto inAppDataSignatureString = javaString ("INAPP_DATA_SIGNATURE"); - auto responseCodeString = javaString ("RESPONSE_CODE"); + return { juceString (LocalRef ((jstring) env->CallObjectMethod (purchase, AndroidPurchase.getOrderId))), + juceString (LocalRef ((jstring) env->CallObjectMethod (purchase, AndroidPurchase.getSku))), + juceString (LocalRef ((jstring) env->CallObjectMethod (purchase, AndroidPurchase.getPackageName))), + Time (env->CallLongMethod (purchase, AndroidPurchase.getPurchaseTime)).toString (true, true, true, true), + juceString (LocalRef ((jstring) env->CallObjectMethod (purchase, AndroidPurchase.getPurchaseToken))) }; + } - auto pd = LocalRef ((jstring) env->CallObjectMethod (intentData, AndroidIntent.getStringExtra, inAppPurchaseDataString.get())); - auto sig = LocalRef ((jstring) env->CallObjectMethod (intentData, AndroidIntent.getStringExtra, inAppDataSignatureString.get())); - auto purchaseDataString = pd.get() != 0 ? juceString (pd.get()) : String(); - auto dataSignatureString = sig.get() != 0 ? juceString (sig.get()) : String(); + static InAppPurchases::Product buildProduct (LocalRef productSkuDetails) + { + if (productSkuDetails == nullptr) + return {}; - var responseData = JSON::parse (purchaseDataString); + auto* env = getEnv(); - auto responseCode = env->CallIntMethod (intentData, AndroidIntent.getIntExtra, responseCodeString.get()); - auto statusCodeUserString = statusCodeToUserString (responseCode); + return { juceString (LocalRef ((jstring) env->CallObjectMethod (productSkuDetails, SkuDetails.getSku))), + juceString (LocalRef ((jstring) env->CallObjectMethod (productSkuDetails, SkuDetails.getTitle))), + juceString (LocalRef ((jstring) env->CallObjectMethod (productSkuDetails, SkuDetails.getDescription))), + juceString (LocalRef ((jstring) env->CallObjectMethod (productSkuDetails, SkuDetails.getPrice))), + juceString (LocalRef ((jstring) env->CallObjectMethod (productSkuDetails, SkuDetails.getPriceCurrencyCode))) }; + } - if (auto* object = responseData.getDynamicObject()) + static String getStatusDescriptionFromResponseCode (int responseCode) + { + switch (responseCode) { - auto& props = object->getProperties(); - - static const Identifier orderIdIdentifier ("orderId"), - packageNameIdentifier ("packageName"), - productIdIdentifier ("productId"), - purchaseTimeIdentifier ("purchaseTime"), - purchaseTokenIdentifier ("purchaseToken"), - developerPayloadIdentifier ("developerPayload"); - - var orderId = props[orderIdIdentifier]; - var packageName = props[packageNameIdentifier]; - var productId = props[productIdIdentifier]; - var purchaseTime = props[purchaseTimeIdentifier]; - var purchaseToken = props[purchaseTokenIdentifier]; - var developerPayload = props[developerPayloadIdentifier]; - - auto purchaseTimeString = Time (purchaseTime.toString().getLargeIntValue()) - .toString (true, true, true, true); - - notifyAboutPurchaseResult ({ orderId.toString(), productId.toString(), packageName.toString(), - purchaseTimeString, purchaseToken.toString() }, - true, statusCodeUserString); - return; + case 0: return NEEDS_TRANS ("Success"); + case 1: return NEEDS_TRANS ("Cancelled by user"); + case 2: return NEEDS_TRANS ("Service unavailable"); + case 3: return NEEDS_TRANS ("Billing unavailable"); + case 4: return NEEDS_TRANS ("Item unavailable"); + case 5: return NEEDS_TRANS ("Internal error"); + case 6: return NEEDS_TRANS ("Generic error"); + case 7: return NEEDS_TRANS ("Item already owned"); + case 8: return NEEDS_TRANS ("Item not owned"); + default: return NEEDS_TRANS ("Unknown status"); } + } - notifyAboutPurchaseResult ({}, false, statusCodeUserString); + static bool wasSuccessful (int responseCode) + { + return responseCode == 0; } - //============================================================================== - static String statusCodeToUserString (int statusCode) + void purchaseCompleted (jobject purchase, int responseCode) { - switch (statusCode) - { - case 0: return NEEDS_TRANS ("Success"); - case 1: return NEEDS_TRANS ("Cancelled by user"); - case 2: return NEEDS_TRANS ("Service unavailable"); - case 3: return NEEDS_TRANS ("Billing unavailable"); - case 4: return NEEDS_TRANS ("Item unavailable"); - case 5: return NEEDS_TRANS ("Internal error"); - case 6: return NEEDS_TRANS ("Generic error"); - case 7: return NEEDS_TRANS ("Item already owned"); - case 8: return NEEDS_TRANS ("Item not owned"); - default: jassertfalse; return NEEDS_TRANS ("Unknown status"); - } + notifyListenersAboutPurchase (buildPurchase (LocalRef (purchase)), + wasSuccessful (responseCode), + getStatusDescriptionFromResponseCode (responseCode)); + } + + void purchaseConsumed (jstring productIdentifier, int responseCode) + { + notifyListenersAboutConsume (juceString (LocalRef (productIdentifier)), + wasSuccessful (responseCode), + getStatusDescriptionFromResponseCode (responseCode)); + } + + void updateSkuDetails (jobject skuDetailsList) + { + jassert (! skuDetailsQueryCallbackQueue.empty()); + skuDetailsQueryCallbackQueue.front() (LocalRef (skuDetailsList)); + skuDetailsQueryCallbackQueue.pop(); + } + + void updatePurchasesList (jobject purchasesList) + { + jassert (! purchasesListQueryCallbackQueue.empty()); + purchasesListQueryCallbackQueue.front() (LocalRef (purchasesList)); + purchasesListQueryCallbackQueue.pop(); } //============================================================================== InAppPurchases& owner; - GlobalRef inAppBillingService, serviceConnection; - std::unique_ptr threadPool; + GlobalRef billingClient; - CriticalSection getProductsInformationJobResultsLock, - getProductsBoughtJobResultsLock, - consumePurchaseJobResultsLock; + std::queue)>> skuDetailsQueryCallbackQueue, + purchasesListQueryCallbackQueue; - Array> getProductsInformationJobResults; - Array getProductsBoughtJobResults; - Array consumePurchaseJobResults; + //============================================================================== + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Pimpl) }; -//============================================================================== -void juce_inAppPurchaseCompleted (void* intentData) -{ - if (auto* instance = InAppPurchases::getInstance()) - instance->pimpl->inAppPurchaseCompleted (static_cast (intentData)); -} +InAppPurchases::Pimpl::JuceBillingClient_Class InAppPurchases::Pimpl::JuceBillingClient; } // namespace juce diff --git a/modules/juce_product_unlocking/native/juce_ios_InAppPurchases.cpp b/modules/juce_product_unlocking/native/juce_ios_InAppPurchases.cpp index cc25f5ec..3d66bd06 100644 --- a/modules/juce_product_unlocking/native/juce_ios_InAppPurchases.cpp +++ b/modules/juce_product_unlocking/native/juce_ios_InAppPurchases.cpp @@ -196,7 +196,7 @@ struct InAppPurchases::Pimpl : public SKDelegateAndPaymentObserver [productsRequest start]; } - void purchaseProduct (const String& productIdentifier, bool, const StringArray&, bool) + void purchaseProduct (const String& productIdentifier, const String&, bool) { if (! [SKPaymentQueue canMakePayments]) { diff --git a/modules/juce_video/juce_video.h b/modules/juce_video/juce_video.h index dc1fd760..499c080a 100644 --- a/modules/juce_video/juce_video.h +++ b/modules/juce_video/juce_video.h @@ -34,17 +34,17 @@ BEGIN_JUCE_MODULE_DECLARATION - ID: juce_video - vendor: juce - version: 5.4.5 - name: JUCE video playback and capture classes - description: Classes for playing video and capturing camera input. - website: http://www.juce.com/juce - license: GPL/Commercial - - dependencies: juce_gui_extra - OSXFrameworks: AVKit AVFoundation CoreMedia - iOSFrameworks: AVKit AVFoundation CoreMedia + ID: juce_video + vendor: juce + version: 5.4.6 + name: JUCE video playback and capture classes + description: Classes for playing video and capturing camera input. + website: http://www.juce.com/juce + license: GPL/Commercial + + dependencies: juce_gui_extra + OSXFrameworks: AVKit AVFoundation CoreMedia + iOSFrameworks: AVKit AVFoundation CoreMedia END_JUCE_MODULE_DECLARATION diff --git a/modules/juce_video/native/juce_android_CameraDevice.h b/modules/juce_video/native/juce_android_CameraDevice.h index 2eedb921..ae1aa9e5 100644 --- a/modules/juce_video/native/juce_android_CameraDevice.h +++ b/modules/juce_video/native/juce_android_CameraDevice.h @@ -1608,7 +1608,7 @@ private: // When exception occurs, CameraCaptureSession.close will never finish, so // we should not wait for it. For fatal error an exception does occur, but - // it is catched internally in Java... + // it is caught internally in Java... if (jniCheckHasExceptionOccurredAndClear() || scopedCameraDevice.fatalErrorOccurred.get()) { JUCE_CAMERA_LOG ("Exception or fatal error occurred while closing Capture Session, closing by force"); diff --git a/modules/juce_video/native/juce_ios_CameraDevice.h b/modules/juce_video/native/juce_ios_CameraDevice.h index edefe326..18a881cf 100644 --- a/modules/juce_video/native/juce_ios_CameraDevice.h +++ b/modules/juce_video/native/juce_ios_CameraDevice.h @@ -746,7 +746,7 @@ private: JUCE_CAMERA_LOG ("Available image codec types: " + typesString); JUCE_CAMERA_LOG ("Still image stabilization supported: " + String ((int) stillImageOutput.stillImageStabilizationSupported)); - JUCE_CAMERA_LOG ("Automatically enableds still image stabilization when available: " + String ((int) stillImageOutput.automaticallyEnablesStillImageStabilizationWhenAvailable)); + JUCE_CAMERA_LOG ("Automatically enables still image stabilization when available: " + String ((int) stillImageOutput.automaticallyEnablesStillImageStabilizationWhenAvailable)); JUCE_CAMERA_LOG ("Output settings for image output: " + nsStringToJuce ([stillImageOutput.outputSettings description])); }