JUCE breaking changes
=====================
+Version 5.4.6
+=============
+
+Change
+------
+AudioProcessorValueTreeState::getRawParameterValue now returns a
+std::atomic<float>* 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<float>* instead of a float*.
+
+Rationale
+---------
+Returning a std::atomic<float>* 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
This file just lists the more notable headline features. For more detailed info\r
about minor changes and bugfixes, please see the git log!\r
\r
+Version 5.4.6\r
+ - Fixed compatibility with macOS versions below 10.11\r
+ - Multiple thread safety improvements\r
+ - Added dynamic parameter and parameter group names\r
+ - Updated to the latest Android In-App Purchases API\r
+ - Improvements to the Windows message queue under high load\r
+ - Replaced WaitableEvent internals with std::condition_variable\r
+ - Fixed some macOS text alignment issues\r
+\r
Version 5.4.5\r
- Improved message queue performance on Linux\r
- Added missing lifecycle callbacks on Android Q\r
\r
#pragma once\r
\r
-#include "../JuceLibraryCode/JuceHeader.h"\r
+#include <JuceHeader.h>\r
\r
#ifndef PIP_DEMO_UTILITIES_INCLUDED\r
#define PIP_DEMO_UTILITIES_INCLUDED 1\r
setLEDProgram (*activeBlock);\r
}\r
\r
- // Make the on screen Lighpad component visible\r
+ // Make the on screen Lightpad component visible\r
lightpadComponent.setVisible (true);\r
infoLabel.setVisible (false);\r
\r
return;\r
}\r
\r
- // If there is no ActiveLED obejct for this LED then create one,\r
+ // If there is no ActiveLED object for this LED then create one,\r
// add it to the array, set the LED on the Block and return\r
if (index < 0)\r
{\r
button->removeListener (this);\r
}\r
\r
- /** Called periodically to update the tooltip with inforamtion about the Block */\r
+ /** Called periodically to update the tooltip with information about the Block */\r
void updateStatsAndTooltip()\r
{\r
// Get the battery level of this Block and inform any subclasses\r
}\r
\r
//==============================================================================\r
+ TooltipWindow tooltipWindow;\r
+\r
PhysicalTopologySource topologySource;\r
OwnedArray<BlockComponent> blockComponents;\r
BlockComponent* masterBlockComponent = nullptr;\r
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"
"../../../../../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"
"../../../../../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"
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)
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)
<?xml version="1.0" encoding="utf-8"?>
-<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="5.4.5"
+<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="5.4.6"
package="com.juce.demorunner">
<supports-screens android:smallScreens="true" android:normalScreens="true" android:largeScreens="true" android:anyDensity="true"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
+ <uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-feature android:glEsVersion="0x00030000" android:required="true"/>
<application android:label="@string/app_name" android:name="com.roli.juce.JuceApp" android:icon="@drawable/icon" android:hardwareAccelerated="false">
\r
#pragma once\r
\r
-#include "../JuceLibraryCode/JuceHeader.h"\r
+#include <JuceHeader.h>\r
\r
#ifndef PIP_DEMO_UTILITIES_INCLUDED\r
#define PIP_DEMO_UTILITIES_INCLUDED 1\r
jcenter()
}
dependencies {
- classpath 'com.android.tools.build:gradle:3.2.1'
+ classpath 'com.android.tools.build:gradle:3.5.3'
}
}
-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
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
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
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+</dict>
+</plist>
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
-</dict>
-</plist>
isa = PBXBuildFile;
fileRef = 96D99A08027CA35D6A4E5CFD;
};
+ 47ED2C78B05B8A6A00E36C46 = {
+ isa = PBXBuildFile;
+ fileRef = 685A261BE78585293F3EAD36;
+ };
D3D8CDCE42E8BE31C7247E38 = {
isa = PBXBuildFile;
fileRef = 0ECB4FCD24794CE516792552;
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;
path = "../../../../modules/juce_audio_basics";
sourceTree = "SOURCE_ROOT";
};
+ 685A261BE78585293F3EAD36 = {
+ isa = PBXFileReference;
+ lastKnownFileType = folder;
+ name = Assets;
+ path = ../../../Assets;
+ sourceTree = "<group>";
+ };
6C198AF93E1F6E682189E2F6 = {
isa = PBXFileReference;
lastKnownFileType = file;
D87DCD5DA4EC8D78DFF37FCC = {
isa = PBXGroup;
children = (
+ 685A261BE78585293F3EAD36,
0ECB4FCD24794CE516792552,
388A8209DBB1B08594266121,
5CD17151385A69F1E07FE85B,
"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",
"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",
GCC_WARN_UNUSED_VARIABLE = YES;
ONLY_ACTIVE_ARCH = YES;
PRODUCT_NAME = "DemoRunner";
+ SDKROOT = macosx;
WARNING_CFLAGS = "-Wreorder";
ZERO_LINK = NO;
};
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
PRODUCT_NAME = "DemoRunner";
+ SDKROOT = macosx;
WARNING_CFLAGS = "-Wreorder";
ZERO_LINK = NO;
};
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
+ 47ED2C78B05B8A6A00E36C46,
D3D8CDCE42E8BE31C7247E38,
3B3952A9A14320312EF890A5,
41BAB55E0D992708EF06E2C4,
<key>CFBundleSignature</key>\r
<string>????</string>\r
<key>CFBundleShortVersionString</key>\r
- <string>5.4.5</string>\r
+ <string>5.4.6</string>\r
<key>CFBundleVersion</key>\r
- <string>5.4.5</string>\r
+ <string>5.4.6</string>\r
<key>NSHumanReadableCopyright</key>\r
<string>Copyright (c) 2018 - ROLI Ltd.</string>\r
<key>NSHighResolutionCapable</key>\r
<Optimization>Disabled</Optimization>\r
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\r
<AdditionalIncludeDirectories>..\..\JuceLibraryCode;..\..\..\..\modules;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
- <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.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)</PreprocessorDefinitions>\r
+ <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)</PreprocessorDefinitions>\r
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>\r
<RuntimeTypeInfo>true</RuntimeTypeInfo>\r
<PrecompiledHeader/>\r
<ClCompile>\r
<Optimization>Full</Optimization>\r
<AdditionalIncludeDirectories>..\..\JuceLibraryCode;..\..\..\..\modules;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
- <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.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)</PreprocessorDefinitions>\r
+ <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)</PreprocessorDefinitions>\r
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>\r
<RuntimeTypeInfo>true</RuntimeTypeInfo>\r
<PrecompiledHeader/>\r
<ClCompile Include="..\..\..\..\modules\juce_core\misc\juce_RuntimePermissions.cpp">\r
<ExcludedFromBuild>true</ExcludedFromBuild>\r
</ClCompile>\r
- <ClCompile Include="..\..\..\..\modules\juce_core\misc\juce_StdFunctionCompat.cpp">\r
- <ExcludedFromBuild>true</ExcludedFromBuild>\r
- </ClCompile>\r
<ClCompile Include="..\..\..\..\modules\juce_core\misc\juce_Uuid.cpp">\r
<ExcludedFromBuild>true</ExcludedFromBuild>\r
</ClCompile>\r
<ClCompile Include="..\..\..\..\modules\juce_core\threads\juce_TimeSliceThread.cpp">\r
<ExcludedFromBuild>true</ExcludedFromBuild>\r
</ClCompile>\r
+ <ClCompile Include="..\..\..\..\modules\juce_core\threads\juce_WaitableEvent.cpp">\r
+ <ExcludedFromBuild>true</ExcludedFromBuild>\r
+ </ClCompile>\r
<ClCompile Include="..\..\..\..\modules\juce_core\time\juce_PerformanceCounter.cpp">\r
<ExcludedFromBuild>true</ExcludedFromBuild>\r
</ClCompile>\r
<ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_ConsoleApplication.h"/>\r
<ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_Result.h"/>\r
<ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_RuntimePermissions.h"/>\r
- <ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_StdFunctionCompat.h"/>\r
<ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_Uuid.h"/>\r
<ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_WindowsRegistry.h"/>\r
<ClInclude Include="..\..\..\..\modules\juce_core\native\juce_android_JNIHelpers.h"/>\r
<ClCompile Include="..\..\..\..\modules\juce_core\misc\juce_RuntimePermissions.cpp">\r
<Filter>JUCE Modules\juce_core\misc</Filter>\r
</ClCompile>\r
- <ClCompile Include="..\..\..\..\modules\juce_core\misc\juce_StdFunctionCompat.cpp">\r
- <Filter>JUCE Modules\juce_core\misc</Filter>\r
- </ClCompile>\r
<ClCompile Include="..\..\..\..\modules\juce_core\misc\juce_Uuid.cpp">\r
<Filter>JUCE Modules\juce_core\misc</Filter>\r
</ClCompile>\r
<ClCompile Include="..\..\..\..\modules\juce_core\threads\juce_TimeSliceThread.cpp">\r
<Filter>JUCE Modules\juce_core\threads</Filter>\r
</ClCompile>\r
+ <ClCompile Include="..\..\..\..\modules\juce_core\threads\juce_WaitableEvent.cpp">\r
+ <Filter>JUCE Modules\juce_core\threads</Filter>\r
+ </ClCompile>\r
<ClCompile Include="..\..\..\..\modules\juce_core\time\juce_PerformanceCounter.cpp">\r
<Filter>JUCE Modules\juce_core\time</Filter>\r
</ClCompile>\r
<ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_RuntimePermissions.h">\r
<Filter>JUCE Modules\juce_core\misc</Filter>\r
</ClInclude>\r
- <ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_StdFunctionCompat.h">\r
- <Filter>JUCE Modules\juce_core\misc</Filter>\r
- </ClInclude>\r
<ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_Uuid.h">\r
<Filter>JUCE Modules\juce_core\misc</Filter>\r
</ClInclude>\r
#include <windows.h>\r
\r
VS_VERSION_INFO VERSIONINFO\r
-FILEVERSION 5,4,5,0\r
+FILEVERSION 5,4,6,0\r
BEGIN\r
BLOCK "StringFileInfo"\r
BEGIN\r
VALUE "CompanyName", "ROLI Ltd.\0"\r
VALUE "LegalCopyright", "Copyright (c) 2018 - ROLI Ltd.\0"\r
VALUE "FileDescription", "DemoRunner\0"\r
- VALUE "FileVersion", "5.4.5\0"\r
+ VALUE "FileVersion", "5.4.6\0"\r
VALUE "ProductName", "DemoRunner\0"\r
- VALUE "ProductVersion", "5.4.5\0"\r
+ VALUE "ProductVersion", "5.4.6\0"\r
END\r
END\r
\r
<Optimization>Disabled</Optimization>\r
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\r
<AdditionalIncludeDirectories>..\..\JuceLibraryCode;..\..\..\..\modules;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
- <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.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)</PreprocessorDefinitions>\r
+ <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)</PreprocessorDefinitions>\r
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>\r
<RuntimeTypeInfo>true</RuntimeTypeInfo>\r
<PrecompiledHeader/>\r
<ClCompile>\r
<Optimization>Full</Optimization>\r
<AdditionalIncludeDirectories>..\..\JuceLibraryCode;..\..\..\..\modules;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
- <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.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)</PreprocessorDefinitions>\r
+ <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)</PreprocessorDefinitions>\r
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>\r
<RuntimeTypeInfo>true</RuntimeTypeInfo>\r
<PrecompiledHeader/>\r
<ClCompile Include="..\..\..\..\modules\juce_core\misc\juce_RuntimePermissions.cpp">\r
<ExcludedFromBuild>true</ExcludedFromBuild>\r
</ClCompile>\r
- <ClCompile Include="..\..\..\..\modules\juce_core\misc\juce_StdFunctionCompat.cpp">\r
- <ExcludedFromBuild>true</ExcludedFromBuild>\r
- </ClCompile>\r
<ClCompile Include="..\..\..\..\modules\juce_core\misc\juce_Uuid.cpp">\r
<ExcludedFromBuild>true</ExcludedFromBuild>\r
</ClCompile>\r
<ClCompile Include="..\..\..\..\modules\juce_core\threads\juce_TimeSliceThread.cpp">\r
<ExcludedFromBuild>true</ExcludedFromBuild>\r
</ClCompile>\r
+ <ClCompile Include="..\..\..\..\modules\juce_core\threads\juce_WaitableEvent.cpp">\r
+ <ExcludedFromBuild>true</ExcludedFromBuild>\r
+ </ClCompile>\r
<ClCompile Include="..\..\..\..\modules\juce_core\time\juce_PerformanceCounter.cpp">\r
<ExcludedFromBuild>true</ExcludedFromBuild>\r
</ClCompile>\r
<ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_ConsoleApplication.h"/>\r
<ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_Result.h"/>\r
<ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_RuntimePermissions.h"/>\r
- <ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_StdFunctionCompat.h"/>\r
<ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_Uuid.h"/>\r
<ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_WindowsRegistry.h"/>\r
<ClInclude Include="..\..\..\..\modules\juce_core\native\juce_android_JNIHelpers.h"/>\r
<ClCompile Include="..\..\..\..\modules\juce_core\misc\juce_RuntimePermissions.cpp">\r
<Filter>JUCE Modules\juce_core\misc</Filter>\r
</ClCompile>\r
- <ClCompile Include="..\..\..\..\modules\juce_core\misc\juce_StdFunctionCompat.cpp">\r
- <Filter>JUCE Modules\juce_core\misc</Filter>\r
- </ClCompile>\r
<ClCompile Include="..\..\..\..\modules\juce_core\misc\juce_Uuid.cpp">\r
<Filter>JUCE Modules\juce_core\misc</Filter>\r
</ClCompile>\r
<ClCompile Include="..\..\..\..\modules\juce_core\threads\juce_TimeSliceThread.cpp">\r
<Filter>JUCE Modules\juce_core\threads</Filter>\r
</ClCompile>\r
+ <ClCompile Include="..\..\..\..\modules\juce_core\threads\juce_WaitableEvent.cpp">\r
+ <Filter>JUCE Modules\juce_core\threads</Filter>\r
+ </ClCompile>\r
<ClCompile Include="..\..\..\..\modules\juce_core\time\juce_PerformanceCounter.cpp">\r
<Filter>JUCE Modules\juce_core\time</Filter>\r
</ClCompile>\r
<ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_RuntimePermissions.h">\r
<Filter>JUCE Modules\juce_core\misc</Filter>\r
</ClInclude>\r
- <ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_StdFunctionCompat.h">\r
- <Filter>JUCE Modules\juce_core\misc</Filter>\r
- </ClInclude>\r
<ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_Uuid.h">\r
<Filter>JUCE Modules\juce_core\misc</Filter>\r
</ClInclude>\r
#include <windows.h>\r
\r
VS_VERSION_INFO VERSIONINFO\r
-FILEVERSION 5,4,5,0\r
+FILEVERSION 5,4,6,0\r
BEGIN\r
BLOCK "StringFileInfo"\r
BEGIN\r
VALUE "CompanyName", "ROLI Ltd.\0"\r
VALUE "LegalCopyright", "Copyright (c) 2018 - ROLI Ltd.\0"\r
VALUE "FileDescription", "DemoRunner\0"\r
- VALUE "FileVersion", "5.4.5\0"\r
+ VALUE "FileVersion", "5.4.6\0"\r
VALUE "ProductName", "DemoRunner\0"\r
- VALUE "ProductVersion", "5.4.5\0"\r
+ VALUE "ProductVersion", "5.4.6\0"\r
END\r
END\r
\r
<Optimization>Disabled</Optimization>\r
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\r
<AdditionalIncludeDirectories>..\..\JuceLibraryCode;..\..\..\..\modules;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
- <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.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)</PreprocessorDefinitions>\r
+ <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)</PreprocessorDefinitions>\r
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>\r
<RuntimeTypeInfo>true</RuntimeTypeInfo>\r
<PrecompiledHeader/>\r
<ClCompile>\r
<Optimization>Full</Optimization>\r
<AdditionalIncludeDirectories>..\..\JuceLibraryCode;..\..\..\..\modules;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
- <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.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)</PreprocessorDefinitions>\r
+ <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)</PreprocessorDefinitions>\r
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>\r
<RuntimeTypeInfo>true</RuntimeTypeInfo>\r
<PrecompiledHeader/>\r
<ClCompile Include="..\..\..\..\modules\juce_core\misc\juce_RuntimePermissions.cpp">\r
<ExcludedFromBuild>true</ExcludedFromBuild>\r
</ClCompile>\r
- <ClCompile Include="..\..\..\..\modules\juce_core\misc\juce_StdFunctionCompat.cpp">\r
- <ExcludedFromBuild>true</ExcludedFromBuild>\r
- </ClCompile>\r
<ClCompile Include="..\..\..\..\modules\juce_core\misc\juce_Uuid.cpp">\r
<ExcludedFromBuild>true</ExcludedFromBuild>\r
</ClCompile>\r
<ClCompile Include="..\..\..\..\modules\juce_core\threads\juce_TimeSliceThread.cpp">\r
<ExcludedFromBuild>true</ExcludedFromBuild>\r
</ClCompile>\r
+ <ClCompile Include="..\..\..\..\modules\juce_core\threads\juce_WaitableEvent.cpp">\r
+ <ExcludedFromBuild>true</ExcludedFromBuild>\r
+ </ClCompile>\r
<ClCompile Include="..\..\..\..\modules\juce_core\time\juce_PerformanceCounter.cpp">\r
<ExcludedFromBuild>true</ExcludedFromBuild>\r
</ClCompile>\r
<ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_ConsoleApplication.h"/>\r
<ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_Result.h"/>\r
<ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_RuntimePermissions.h"/>\r
- <ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_StdFunctionCompat.h"/>\r
<ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_Uuid.h"/>\r
<ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_WindowsRegistry.h"/>\r
<ClInclude Include="..\..\..\..\modules\juce_core\native\juce_android_JNIHelpers.h"/>\r
<ClCompile Include="..\..\..\..\modules\juce_core\misc\juce_RuntimePermissions.cpp">\r
<Filter>JUCE Modules\juce_core\misc</Filter>\r
</ClCompile>\r
- <ClCompile Include="..\..\..\..\modules\juce_core\misc\juce_StdFunctionCompat.cpp">\r
- <Filter>JUCE Modules\juce_core\misc</Filter>\r
- </ClCompile>\r
<ClCompile Include="..\..\..\..\modules\juce_core\misc\juce_Uuid.cpp">\r
<Filter>JUCE Modules\juce_core\misc</Filter>\r
</ClCompile>\r
<ClCompile Include="..\..\..\..\modules\juce_core\threads\juce_TimeSliceThread.cpp">\r
<Filter>JUCE Modules\juce_core\threads</Filter>\r
</ClCompile>\r
+ <ClCompile Include="..\..\..\..\modules\juce_core\threads\juce_WaitableEvent.cpp">\r
+ <Filter>JUCE Modules\juce_core\threads</Filter>\r
+ </ClCompile>\r
<ClCompile Include="..\..\..\..\modules\juce_core\time\juce_PerformanceCounter.cpp">\r
<Filter>JUCE Modules\juce_core\time</Filter>\r
</ClCompile>\r
<ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_RuntimePermissions.h">\r
<Filter>JUCE Modules\juce_core\misc</Filter>\r
</ClInclude>\r
- <ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_StdFunctionCompat.h">\r
- <Filter>JUCE Modules\juce_core\misc</Filter>\r
- </ClInclude>\r
<ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_Uuid.h">\r
<Filter>JUCE Modules\juce_core\misc</Filter>\r
</ClInclude>\r
#include <windows.h>\r
\r
VS_VERSION_INFO VERSIONINFO\r
-FILEVERSION 5,4,5,0\r
+FILEVERSION 5,4,6,0\r
BEGIN\r
BLOCK "StringFileInfo"\r
BEGIN\r
VALUE "CompanyName", "ROLI Ltd.\0"\r
VALUE "LegalCopyright", "Copyright (c) 2018 - ROLI Ltd.\0"\r
VALUE "FileDescription", "DemoRunner\0"\r
- VALUE "FileVersion", "5.4.5\0"\r
+ VALUE "FileVersion", "5.4.6\0"\r
VALUE "ProductName", "DemoRunner\0"\r
- VALUE "ProductVersion", "5.4.5\0"\r
+ VALUE "ProductVersion", "5.4.6\0"\r
END\r
END\r
\r
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>com.apple.developer.icloud-container-identifiers</key>
+ <array>
+ <string>iCloud.$(CFBundleIdentifier)</string>
+ </array>
+ <key>com.apple.developer.icloud-services</key>
+ <array>
+ <string>CloudDocuments</string>
+ </array>
+ <key>com.apple.developer.ubiquity-container-identifiers</key>
+ <array>
+ <string>iCloud.$(CFBundleIdentifier)</string>
+ </array>
+</dict>
+</plist>
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
- <key>com.apple.developer.icloud-container-identifiers</key>
- <array>
- <string>iCloud.$(CFBundleIdentifier)</string>
- </array>
- <key>com.apple.developer.icloud-services</key>
- <array>
- <string>CloudDocuments</string>
- </array>
- <key>com.apple.developer.ubiquity-container-identifiers</key>
- <array>
- <string>iCloud.$(CFBundleIdentifier)</string>
- </array>
-</dict>
-</plist>
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;
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;
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;
"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",
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;
"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",
<key>CFBundleSignature</key>\r
<string>????</string>\r
<key>CFBundleShortVersionString</key>\r
- <string>5.4.5</string>\r
+ <string>5.4.6</string>\r
<key>CFBundleVersion</key>\r
- <string>5.4.5</string>\r
+ <string>5.4.6</string>\r
<key>NSHumanReadableCopyright</key>\r
<string>Copyright (c) 2018 - ROLI Ltd.</string>\r
<key>NSHighResolutionCapable</key>\r
<?xml version="1.0" encoding="UTF-8"?>\r
\r
-<JUCERPROJECT name="DemoRunner" projectType="guiapp" jucerVersion="5.4.5" defines="JUCE_DEMO_RUNNER=1 JUCE_UNIT_TESTS=1"\r
- bundleIdentifier="com.juce.demorunner" version="5.4.5" companyName="ROLI Ltd."\r
+<JUCERPROJECT name="DemoRunner" projectType="guiapp" jucerVersion="5.4.6" defines="JUCE_DEMO_RUNNER=1 JUCE_UNIT_TESTS=1"\r
+ bundleIdentifier="com.juce.demorunner" version="5.4.6" companyName="ROLI Ltd."\r
companyCopyright="Copyright (c) 2018 - ROLI Ltd." companyWebsite="https://www.juce.com/"\r
companyEmail="info@juce.com" id="yj7xMM" reportAppUsage="1">\r
<MAINGROUP id="G8kbr7" name="DemoRunner">\r
</MAINGROUP>\r
<EXPORTFORMATS>\r
<XCODE_MAC targetFolder="Builds/MacOSX" smallIcon="YyqWd2" bigIcon="YyqWd2"\r
- customXcodeResourceFolders="../Audio ../BLOCKS ../DSP ../GUI ../Utilities"\r
+ customXcodeResourceFolders="../Assets ../Audio ../BLOCKS ../DSP ../GUI ../Utilities"\r
microphonePermissionNeeded="1" cameraPermissionNeeded="1">\r
<CONFIGURATIONS>\r
<CONFIGURATION isDebug="1" name="Debug" recommendedWarnings="LLVM"/>\r
\r
#define JUCE_USE_DARK_SPLASH_SCREEN 1\r
\r
-#define JUCE_PROJUCER_VERSION 0x50405\r
+#define JUCE_PROJUCER_VERSION 0x50406\r
\r
//==============================================================================\r
#define JUCE_MODULE_AVAILABLE_juce_analytics 1\r
//==============================================================================\r
// juce_events flags:\r
\r
-#ifndef JUCE_EXECUTE_APP_SUSPEND_ON_IOS_BACKGROUND_TASK\r
- //#define JUCE_EXECUTE_APP_SUSPEND_ON_IOS_BACKGROUND_TASK 0\r
+#ifndef JUCE_EXECUTE_APP_SUSPEND_ON_BACKGROUND_TASK\r
+ //#define JUCE_EXECUTE_APP_SUSPEND_ON_BACKGROUND_TASK 0\r
#endif\r
\r
//==============================================================================\r
{\r
const char* const projectName = "DemoRunner";\r
const char* const companyName = "ROLI Ltd.";\r
- const char* const versionString = "5.4.5";\r
- const int versionNumber = 0x50405;\r
+ const char* const versionString = "5.4.6";\r
+ const int versionNumber = 0x50406;\r
}\r
#endif\r
==============================================================================\r
*/\r
\r
-#include "../JuceLibraryCode/JuceHeader.h"\r
+#include <JuceHeader.h>\r
#include "../../../Assets/DemoUtilities.h"\r
#include "JUCEDemos.h"\r
\r
==============================================================================\r
*/\r
\r
-#include "../JuceLibraryCode/JuceHeader.h"\r
+#include <JuceHeader.h>\r
#include "../../../Assets/DemoUtilities.h"\r
#include "JUCEDemos.h"\r
\r
==============================================================================\r
*/\r
\r
-#include "../JuceLibraryCode/JuceHeader.h"\r
+#include <JuceHeader.h>\r
#include "../../../Assets/DemoUtilities.h"\r
#include "JUCEDemos.h"\r
\r
==============================================================================\r
*/\r
\r
-#include "../JuceLibraryCode/JuceHeader.h"\r
+#include <JuceHeader.h>\r
#include "../../Assets/DemoUtilities.h"\r
\r
#include "UI/MainComponent.h"\r
//==============================================================================\r
DemoContentComponent::DemoContentComponent (Component& mainComponent, std::function<void(bool)> callback)\r
: TabbedComponent (TabbedButtonBar::Orientation::TabsAtTop),\r
- demoChangedCallback (callback)\r
+ demoChangedCallback (std::move (callback))\r
{\r
demoContent.reset (new DemoContent());\r
addTab ("Demo", Colours::transparentBlack, demoContent.get(), false);\r
\r
#pragma once\r
\r
-#include "../JuceLibraryCode/JuceHeader.h"\r
+#include <JuceHeader.h>\r
#include "../Demos/JUCEDemos.h"\r
\r
struct DemoContent;\r
\r
#pragma once\r
\r
-#include "../JuceLibraryCode/JuceHeader.h"\r
+#include <JuceHeader.h>\r
#include "DemoContentComponent.h"\r
\r
//==============================================================================\r
\r
r.removeFromLeft (verticalDividerBar->getRight());\r
\r
- styleBox.setBounds (r.removeFromBottom (26));\r
- r.removeFromBottom (8);\r
-\r
int labelWidth = 60;\r
\r
+ auto styleArea = r.removeFromBottom (26);\r
+ styleArea.removeFromLeft (labelWidth);\r
+ styleBox.setBounds (styleArea);\r
+ r.removeFromBottom (8);\r
+\r
auto row = r.removeFromBottom (30);\r
row.removeFromLeft (labelWidth);\r
boldToggle.setBounds (row.removeFromLeft (row.getWidth() / 2));\r
\r
Label heightLabel { {}, "Height:" },\r
kerningLabel { {}, "Kerning:" },\r
- scaleLabel { "Scale:" },\r
- styleLabel { "Style" };\r
+ scaleLabel { {}, "Scale:" },\r
+ styleLabel { {}, "Style:" };\r
\r
ToggleButton boldToggle { "Bold" },\r
italicToggle { "Italic" };\r
if (selectedFile.existsAsFile())\r
imagePreview.setImage (ImageCache::getFromFile (selectedFile));\r
\r
- // the image cahce is a handly way to load images from files or directly from memory and\r
+ // the image cache is a handy way to load images from files or directly from memory and\r
// will keep them hanging around for a few seconds in case they are requested elsewhere\r
}\r
\r
//==============================================================================\r
/** The Note class contains text editor used to display and edit the note's contents and will\r
also listen to changes in the text and mark the FileBasedDocument as 'dirty'. This 'dirty'\r
- flag is used to promt the user to save the note when it is closed.\r
+ flag is used to prompt the user to save the note when it is closed.\r
*/\r
class Note : public Component,\r
public FileBasedDocument\r
\r
void clicked() override\r
{\r
- auto* colourSelector = new ColourSelector();\r
+ auto* colourSelector = new ColourSelector (ColourSelector::showAlphaChannel\r
+ | ColourSelector::showColourAtTop\r
+ | ColourSelector::editableColour\r
+ | ColourSelector::showSliders\r
+ | ColourSelector::showColourspace);\r
+\r
colourSelector->setName ("background");\r
colourSelector->setCurrentColour (findColour (TextButton::buttonColourId));\r
colourSelector->addChangeListener (this);\r
OwnedArray<Component> components;\r
std::unique_ptr<BubbleMessageComponent> bubbleMessage;\r
\r
+ TooltipWindow tooltipWindow;\r
+\r
// This little function avoids a bit of code-duplication by adding a component to\r
// our list as well as calling addAndMakeVisible on it..\r
template <typename ComponentType>\r
\r
void processBlock (AudioBuffer<float>& buffer, MidiBuffer&) override\r
{\r
- auto gain = *parameters.getRawParameterValue ("gain");\r
+ float gain = *parameters.getRawParameterValue ("gain");\r
\r
auto totalNumInputChannels = getTotalNumInputChannels();\r
auto totalNumOutputChannels = getTotalNumOutputChannels();\r
\r
#include "../Assets/DemoUtilities.h"\r
\r
+/*\r
+ To finish the setup of this demo, do the following in the Projucer project:\r
+\r
+ 1. In the project settings, set the "Bundle Identifier" to com.roli.juceInAppPurchaseSample\r
+ 2. In the Android exporter settings, change the following settings:\r
+ - "In-App Billing" - Enabled\r
+ - "Key Signing: key.store" - path to InAppPurchase.keystore file in examples/Assets/Signing\r
+ - "Key Signing: key.store.password" - amazingvoices\r
+ - "Key Signing: key-alias" - InAppPurchase\r
+ - "Key Signing: key.alias.password" - amazingvoices\r
+ 3. Re-save the project\r
+*/\r
+\r
//==============================================================================\r
class VoicePurchases : private InAppPurchases::Listener\r
{\r
purchaseInProgress = true;\r
\r
product.purchaseInProgress = true;\r
- InAppPurchases::getInstance()->purchaseProduct (product.identifier, false);\r
+ InAppPurchases::getInstance()->purchaseProduct (product.identifier);\r
\r
guiUpdater.triggerAsyncUpdate();\r
}\r
<< "CPU model: " << SystemStats::getCpuModel() << newLine\r
<< "CPU speed: " << SystemStats::getCpuSpeedInMegahertz() << " MHz" << newLine\r
<< "CPU has MMX: " << (SystemStats::hasMMX() ? "yes" : "no") << newLine\r
+ << "CPU has FMA3: " << (SystemStats::hasFMA3() ? "yes" : "no") << newLine\r
+ << "CPU has FMA4: " << (SystemStats::hasFMA4() ? "yes" : "no") << newLine\r
<< "CPU has SSE: " << (SystemStats::hasSSE() ? "yes" : "no") << newLine\r
<< "CPU has SSE2: " << (SystemStats::hasSSE2() ? "yes" : "no") << newLine\r
<< "CPU has SSE3: " << (SystemStats::hasSSE3() ? "yes" : "no") << newLine\r
{\r
stopFlashing();\r
sendChangeMessage();\r
- // Once we've finsihed flashing send a change message to trigger the next component to flash\r
+ // Once we've finished flashing send a change message to trigger the next component to flash\r
}\r
\r
repaint();\r
addAndMakeVisible (randomColourButton);\r
randomColourButton.onClick = [this] { randomColourButtonClicked(); };\r
\r
- // lay out our components in a psudo random grid\r
+ // lay out our components in a pseudo random grid\r
Rectangle<int> area (0, 100, 150, 150);\r
\r
for (auto* comp : flashingComponents)\r
resultsTree.setRootItem (rootItem.get());\r
}\r
\r
- /** Parses the editors contects as XML. */\r
+ /** Parses the editor's contents as XML. */\r
TreeViewItem* rebuildXml()\r
{\r
parsedXml.reset();\r
return new XmlTreeItem (*parsedXml);\r
}\r
\r
- /** Parses the editors contects as JSON. */\r
+ /** Parses the editor's contents as JSON. */\r
TreeViewItem* rebuildJson()\r
{\r
var parsedJson;\r
<?xml version="1.0" encoding="UTF-8"?>\r
\r
<JUCERPROJECT id="AKfc5m" name="AudioPerformanceTest" projectType="guiapp"\r
- bundleIdentifier="com.juce.AudioPerformanceTest" jucerVersion="5.4.5"\r
+ bundleIdentifier="com.juce.AudioPerformanceTest" jucerVersion="5.4.6"\r
displaySplashScreen="0" reportAppUsage="0" companyName="ROLI Ltd."\r
companyCopyright="ROLI Ltd.">\r
<MAINGROUP id="b1eVTe" name="AudioPerformanceTest">\r
"../../../../../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"
"../../../../../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"
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)
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)
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
<uses-permission android:name="android.permission.BLUETOOTH"/>
+ <uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE"/>
<uses-permission android:name="android.permission.INTERNET"/>
<application android:label="@string/app_name" android:name="com.roli.juce.JuceApp" android:hardwareAccelerated="false">
<activity android:name="com.roli.juce.JuceActivity" android:label="@string/app_name" android:configChanges="keyboardHidden|orientation|screenSize"
jcenter()
}
dependencies {
- classpath 'com.android.tools.build:gradle:3.2.1'
+ classpath 'com.android.tools.build:gradle:3.5.3'
}
}
-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
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+</dict>
+</plist>
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
-</dict>
-</plist>
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;
GCC_WARN_UNUSED_VARIABLE = YES;
ONLY_ACTIVE_ARCH = YES;
PRODUCT_NAME = "AudioPerformanceTest";
+ SDKROOT = macosx;
WARNING_CFLAGS = "-Wreorder";
ZERO_LINK = NO;
};
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
PRODUCT_NAME = "AudioPerformanceTest";
+ SDKROOT = macosx;
WARNING_CFLAGS = "-Wreorder";
ZERO_LINK = NO;
};
<ClCompile Include="..\..\..\..\modules\juce_core\misc\juce_RuntimePermissions.cpp">\r
<ExcludedFromBuild>true</ExcludedFromBuild>\r
</ClCompile>\r
- <ClCompile Include="..\..\..\..\modules\juce_core\misc\juce_StdFunctionCompat.cpp">\r
- <ExcludedFromBuild>true</ExcludedFromBuild>\r
- </ClCompile>\r
<ClCompile Include="..\..\..\..\modules\juce_core\misc\juce_Uuid.cpp">\r
<ExcludedFromBuild>true</ExcludedFromBuild>\r
</ClCompile>\r
<ClCompile Include="..\..\..\..\modules\juce_core\threads\juce_TimeSliceThread.cpp">\r
<ExcludedFromBuild>true</ExcludedFromBuild>\r
</ClCompile>\r
+ <ClCompile Include="..\..\..\..\modules\juce_core\threads\juce_WaitableEvent.cpp">\r
+ <ExcludedFromBuild>true</ExcludedFromBuild>\r
+ </ClCompile>\r
<ClCompile Include="..\..\..\..\modules\juce_core\time\juce_PerformanceCounter.cpp">\r
<ExcludedFromBuild>true</ExcludedFromBuild>\r
</ClCompile>\r
<ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_ConsoleApplication.h"/>\r
<ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_Result.h"/>\r
<ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_RuntimePermissions.h"/>\r
- <ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_StdFunctionCompat.h"/>\r
<ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_Uuid.h"/>\r
<ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_WindowsRegistry.h"/>\r
<ClInclude Include="..\..\..\..\modules\juce_core\native\juce_android_JNIHelpers.h"/>\r
<ClCompile Include="..\..\..\..\modules\juce_core\misc\juce_RuntimePermissions.cpp">\r
<Filter>JUCE Modules\juce_core\misc</Filter>\r
</ClCompile>\r
- <ClCompile Include="..\..\..\..\modules\juce_core\misc\juce_StdFunctionCompat.cpp">\r
- <Filter>JUCE Modules\juce_core\misc</Filter>\r
- </ClCompile>\r
<ClCompile Include="..\..\..\..\modules\juce_core\misc\juce_Uuid.cpp">\r
<Filter>JUCE Modules\juce_core\misc</Filter>\r
</ClCompile>\r
<ClCompile Include="..\..\..\..\modules\juce_core\threads\juce_TimeSliceThread.cpp">\r
<Filter>JUCE Modules\juce_core\threads</Filter>\r
</ClCompile>\r
+ <ClCompile Include="..\..\..\..\modules\juce_core\threads\juce_WaitableEvent.cpp">\r
+ <Filter>JUCE Modules\juce_core\threads</Filter>\r
+ </ClCompile>\r
<ClCompile Include="..\..\..\..\modules\juce_core\time\juce_PerformanceCounter.cpp">\r
<Filter>JUCE Modules\juce_core\time</Filter>\r
</ClCompile>\r
<ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_RuntimePermissions.h">\r
<Filter>JUCE Modules\juce_core\misc</Filter>\r
</ClInclude>\r
- <ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_StdFunctionCompat.h">\r
- <Filter>JUCE Modules\juce_core\misc</Filter>\r
- </ClInclude>\r
<ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_Uuid.h">\r
<Filter>JUCE Modules\juce_core\misc</Filter>\r
</ClInclude>\r
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+</dict>
+</plist>
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
-</dict>
-</plist>
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;
\r
#define JUCE_USE_DARK_SPLASH_SCREEN 1\r
\r
-#define JUCE_PROJUCER_VERSION 0x50405\r
+#define JUCE_PROJUCER_VERSION 0x50406\r
\r
//==============================================================================\r
#define JUCE_MODULE_AVAILABLE_juce_audio_basics 1\r
//==============================================================================\r
// juce_events flags:\r
\r
-#ifndef JUCE_EXECUTE_APP_SUSPEND_ON_IOS_BACKGROUND_TASK\r
- //#define JUCE_EXECUTE_APP_SUSPEND_ON_IOS_BACKGROUND_TASK 0\r
+#ifndef JUCE_EXECUTE_APP_SUSPEND_ON_BACKGROUND_TASK\r
+ //#define JUCE_EXECUTE_APP_SUSPEND_ON_BACKGROUND_TASK 0\r
#endif\r
\r
//==============================================================================\r
==============================================================================\r
*/\r
\r
-#include "../JuceLibraryCode/JuceHeader.h"\r
+#include <JuceHeader.h>\r
#include "MainComponent.h"\r
\r
Component* createMainContentComponent();\r
\r
#pragma once\r
\r
-#include "../JuceLibraryCode/JuceHeader.h"\r
+#include <JuceHeader.h>\r
#include <mutex>\r
\r
//==============================================================================\r
\r
<JUCERPROJECT id="NTe0XB0ij" name="AudioPluginHost" projectType="guiapp" version="1.0.0"\r
juceFolder="../../../juce" bundleIdentifier="com.roli.juce.pluginhost"\r
- jucerVersion="5.4.5" companyName="ROLI Ltd." displaySplashScreen="0"\r
+ jucerVersion="5.4.6" companyName="ROLI Ltd." displaySplashScreen="0"\r
reportAppUsage="0" companyCopyright="ROLI Ltd.">\r
<EXPORTFORMATS>\r
<XCODE_MAC targetFolder="Builds/MacOSX" rtasFolder="~/SDKs/PT_80_SDK" objCExtraSuffix="M73TRi"\r
<FILE id="c97aUr" name="JUCEAppIcon.png" compile="0" resource="1" file="Source/JUCEAppIcon.png"/>\r
</GROUP>\r
</MAINGROUP>\r
- <JUCEOPTIONS JUCE_WASAPI="1" JUCE_DIRECTSOUND="1" JUCE_ALSA="1" JUCE_QUICKTIME="disabled"\r
- JUCE_USE_FLAC="0" JUCE_USE_OGGVORBIS="0" JUCE_USE_CDBURNER="0"\r
- JUCE_USE_CDREADER="0" JUCE_USE_CAMERA="0" JUCE_PLUGINHOST_AU="1"\r
- JUCE_WEB_BROWSER="0" JUCE_PLUGINHOST_VST3="1" JUCE_PLUGINHOST_LADSPA="1"/>\r
+ <JUCEOPTIONS JUCE_WASAPI="1" JUCE_DIRECTSOUND="1" JUCE_ALSA="1" JUCE_USE_FLAC="0"\r
+ JUCE_USE_OGGVORBIS="0" JUCE_USE_CDBURNER="0" JUCE_USE_CDREADER="0"\r
+ JUCE_USE_CAMERA="0" JUCE_PLUGINHOST_AU="1" JUCE_WEB_BROWSER="0"\r
+ JUCE_PLUGINHOST_VST3="1" JUCE_PLUGINHOST_LADSPA="1"/>\r
<MODULES>\r
<MODULE id="juce_audio_basics" showAllCode="1"/>\r
<MODULE id="juce_audio_devices" showAllCode="1"/>\r
"../../../../../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"
"../../../../../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"
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)
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)
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
+ <uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-feature android:glEsVersion="0x00030000" android:required="true"/>
<application android:label="@string/app_name" android:name="com.roli.juce.JuceApp" android:icon="@drawable/icon" android:hardwareAccelerated="false">
jcenter()
}
dependencies {
- classpath 'com.android.tools.build:gradle:3.2.1'
+ classpath 'com.android.tools.build:gradle:3.5.3'
}
}
-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
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+</dict>
+</plist>
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
-</dict>
-</plist>
isa = PBXBuildFile;
fileRef = 8D8BBC353637DA442C5575DA;
};
+ B288A89F96704F142ED8E939 = {
+ isa = PBXBuildFile;
+ fileRef = 5ACC21AA45BBF48C3C64D56D;
+ };
73E371F1B912FCCAE0CD7E5D = {
isa = PBXBuildFile;
fileRef = 86CA337014D3F67E906FFD28;
isa = PBXBuildFile;
fileRef = D4EBC17BDB7F88CCBC76730B;
};
- B288A89F96704F142ED8E939 = {
- isa = PBXBuildFile;
- fileRef = 5ACC21AA45BBF48C3C64D56D;
- };
851C1165C9E4ACDD19C56A96 = {
isa = PBXBuildFile;
fileRef = 942A0F04EFB8D0B2FF9780BA;
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;
D1C4804CD275CB57A5C89A2D = {
isa = PBXGroup;
children = (
+ 5ACC21AA45BBF48C3C64D56D,
86CA337014D3F67E906FFD28,
D4EBC17BDB7F88CCBC76730B,
- 5ACC21AA45BBF48C3C64D56D,
942A0F04EFB8D0B2FF9780BA,
A4B568E26157FC282214976F,
B0935EBBA4F6E2B05F3D1C0A,
GCC_WARN_UNUSED_VARIABLE = YES;
ONLY_ACTIVE_ARCH = YES;
PRODUCT_NAME = "AudioPluginHost";
+ SDKROOT = macosx;
WARNING_CFLAGS = "-Wreorder";
ZERO_LINK = NO;
};
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
PRODUCT_NAME = "AudioPluginHost";
+ SDKROOT = macosx;
WARNING_CFLAGS = "-Wreorder";
ZERO_LINK = NO;
};
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
+ B288A89F96704F142ED8E939,
73E371F1B912FCCAE0CD7E5D,
21D330A5B13178B12BEAFC3C,
- B288A89F96704F142ED8E939,
851C1165C9E4ACDD19C56A96,
AF42316D915057E930A5624E,
2B4B9CF71F94BDD1E3AC89AE,
<ClCompile Include="..\..\..\..\modules\juce_core\misc\juce_RuntimePermissions.cpp">\r
<ExcludedFromBuild>true</ExcludedFromBuild>\r
</ClCompile>\r
- <ClCompile Include="..\..\..\..\modules\juce_core\misc\juce_StdFunctionCompat.cpp">\r
- <ExcludedFromBuild>true</ExcludedFromBuild>\r
- </ClCompile>\r
<ClCompile Include="..\..\..\..\modules\juce_core\misc\juce_Uuid.cpp">\r
<ExcludedFromBuild>true</ExcludedFromBuild>\r
</ClCompile>\r
<ClCompile Include="..\..\..\..\modules\juce_core\threads\juce_TimeSliceThread.cpp">\r
<ExcludedFromBuild>true</ExcludedFromBuild>\r
</ClCompile>\r
+ <ClCompile Include="..\..\..\..\modules\juce_core\threads\juce_WaitableEvent.cpp">\r
+ <ExcludedFromBuild>true</ExcludedFromBuild>\r
+ </ClCompile>\r
<ClCompile Include="..\..\..\..\modules\juce_core\time\juce_PerformanceCounter.cpp">\r
<ExcludedFromBuild>true</ExcludedFromBuild>\r
</ClCompile>\r
<ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_ConsoleApplication.h"/>\r
<ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_Result.h"/>\r
<ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_RuntimePermissions.h"/>\r
- <ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_StdFunctionCompat.h"/>\r
<ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_Uuid.h"/>\r
<ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_WindowsRegistry.h"/>\r
<ClInclude Include="..\..\..\..\modules\juce_core\native\juce_android_JNIHelpers.h"/>\r
<ClCompile Include="..\..\..\..\modules\juce_core\misc\juce_RuntimePermissions.cpp">\r
<Filter>JUCE Modules\juce_core\misc</Filter>\r
</ClCompile>\r
- <ClCompile Include="..\..\..\..\modules\juce_core\misc\juce_StdFunctionCompat.cpp">\r
- <Filter>JUCE Modules\juce_core\misc</Filter>\r
- </ClCompile>\r
<ClCompile Include="..\..\..\..\modules\juce_core\misc\juce_Uuid.cpp">\r
<Filter>JUCE Modules\juce_core\misc</Filter>\r
</ClCompile>\r
<ClCompile Include="..\..\..\..\modules\juce_core\threads\juce_TimeSliceThread.cpp">\r
<Filter>JUCE Modules\juce_core\threads</Filter>\r
</ClCompile>\r
+ <ClCompile Include="..\..\..\..\modules\juce_core\threads\juce_WaitableEvent.cpp">\r
+ <Filter>JUCE Modules\juce_core\threads</Filter>\r
+ </ClCompile>\r
<ClCompile Include="..\..\..\..\modules\juce_core\time\juce_PerformanceCounter.cpp">\r
<Filter>JUCE Modules\juce_core\time</Filter>\r
</ClCompile>\r
<ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_RuntimePermissions.h">\r
<Filter>JUCE Modules\juce_core\misc</Filter>\r
</ClInclude>\r
- <ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_StdFunctionCompat.h">\r
- <Filter>JUCE Modules\juce_core\misc</Filter>\r
- </ClInclude>\r
<ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_Uuid.h">\r
<Filter>JUCE Modules\juce_core\misc</Filter>\r
</ClInclude>\r
<ClCompile Include="..\..\..\..\modules\juce_core\misc\juce_RuntimePermissions.cpp">\r
<ExcludedFromBuild>true</ExcludedFromBuild>\r
</ClCompile>\r
- <ClCompile Include="..\..\..\..\modules\juce_core\misc\juce_StdFunctionCompat.cpp">\r
- <ExcludedFromBuild>true</ExcludedFromBuild>\r
- </ClCompile>\r
<ClCompile Include="..\..\..\..\modules\juce_core\misc\juce_Uuid.cpp">\r
<ExcludedFromBuild>true</ExcludedFromBuild>\r
</ClCompile>\r
<ClCompile Include="..\..\..\..\modules\juce_core\threads\juce_TimeSliceThread.cpp">\r
<ExcludedFromBuild>true</ExcludedFromBuild>\r
</ClCompile>\r
+ <ClCompile Include="..\..\..\..\modules\juce_core\threads\juce_WaitableEvent.cpp">\r
+ <ExcludedFromBuild>true</ExcludedFromBuild>\r
+ </ClCompile>\r
<ClCompile Include="..\..\..\..\modules\juce_core\time\juce_PerformanceCounter.cpp">\r
<ExcludedFromBuild>true</ExcludedFromBuild>\r
</ClCompile>\r
<ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_ConsoleApplication.h"/>\r
<ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_Result.h"/>\r
<ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_RuntimePermissions.h"/>\r
- <ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_StdFunctionCompat.h"/>\r
<ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_Uuid.h"/>\r
<ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_WindowsRegistry.h"/>\r
<ClInclude Include="..\..\..\..\modules\juce_core\native\juce_android_JNIHelpers.h"/>\r
<ClCompile Include="..\..\..\..\modules\juce_core\misc\juce_RuntimePermissions.cpp">\r
<Filter>JUCE Modules\juce_core\misc</Filter>\r
</ClCompile>\r
- <ClCompile Include="..\..\..\..\modules\juce_core\misc\juce_StdFunctionCompat.cpp">\r
- <Filter>JUCE Modules\juce_core\misc</Filter>\r
- </ClCompile>\r
<ClCompile Include="..\..\..\..\modules\juce_core\misc\juce_Uuid.cpp">\r
<Filter>JUCE Modules\juce_core\misc</Filter>\r
</ClCompile>\r
<ClCompile Include="..\..\..\..\modules\juce_core\threads\juce_TimeSliceThread.cpp">\r
<Filter>JUCE Modules\juce_core\threads</Filter>\r
</ClCompile>\r
+ <ClCompile Include="..\..\..\..\modules\juce_core\threads\juce_WaitableEvent.cpp">\r
+ <Filter>JUCE Modules\juce_core\threads</Filter>\r
+ </ClCompile>\r
<ClCompile Include="..\..\..\..\modules\juce_core\time\juce_PerformanceCounter.cpp">\r
<Filter>JUCE Modules\juce_core\time</Filter>\r
</ClCompile>\r
<ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_RuntimePermissions.h">\r
<Filter>JUCE Modules\juce_core\misc</Filter>\r
</ClInclude>\r
- <ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_StdFunctionCompat.h">\r
- <Filter>JUCE Modules\juce_core\misc</Filter>\r
- </ClInclude>\r
<ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_Uuid.h">\r
<Filter>JUCE Modules\juce_core\misc</Filter>\r
</ClInclude>\r
<ClCompile Include="..\..\..\..\modules\juce_core\misc\juce_RuntimePermissions.cpp">\r
<ExcludedFromBuild>true</ExcludedFromBuild>\r
</ClCompile>\r
- <ClCompile Include="..\..\..\..\modules\juce_core\misc\juce_StdFunctionCompat.cpp">\r
- <ExcludedFromBuild>true</ExcludedFromBuild>\r
- </ClCompile>\r
<ClCompile Include="..\..\..\..\modules\juce_core\misc\juce_Uuid.cpp">\r
<ExcludedFromBuild>true</ExcludedFromBuild>\r
</ClCompile>\r
<ClCompile Include="..\..\..\..\modules\juce_core\threads\juce_TimeSliceThread.cpp">\r
<ExcludedFromBuild>true</ExcludedFromBuild>\r
</ClCompile>\r
+ <ClCompile Include="..\..\..\..\modules\juce_core\threads\juce_WaitableEvent.cpp">\r
+ <ExcludedFromBuild>true</ExcludedFromBuild>\r
+ </ClCompile>\r
<ClCompile Include="..\..\..\..\modules\juce_core\time\juce_PerformanceCounter.cpp">\r
<ExcludedFromBuild>true</ExcludedFromBuild>\r
</ClCompile>\r
<ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_ConsoleApplication.h"/>\r
<ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_Result.h"/>\r
<ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_RuntimePermissions.h"/>\r
- <ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_StdFunctionCompat.h"/>\r
<ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_Uuid.h"/>\r
<ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_WindowsRegistry.h"/>\r
<ClInclude Include="..\..\..\..\modules\juce_core\native\juce_android_JNIHelpers.h"/>\r
<ClCompile Include="..\..\..\..\modules\juce_core\misc\juce_RuntimePermissions.cpp">\r
<Filter>JUCE Modules\juce_core\misc</Filter>\r
</ClCompile>\r
- <ClCompile Include="..\..\..\..\modules\juce_core\misc\juce_StdFunctionCompat.cpp">\r
- <Filter>JUCE Modules\juce_core\misc</Filter>\r
- </ClCompile>\r
<ClCompile Include="..\..\..\..\modules\juce_core\misc\juce_Uuid.cpp">\r
<Filter>JUCE Modules\juce_core\misc</Filter>\r
</ClCompile>\r
<ClCompile Include="..\..\..\..\modules\juce_core\threads\juce_TimeSliceThread.cpp">\r
<Filter>JUCE Modules\juce_core\threads</Filter>\r
</ClCompile>\r
+ <ClCompile Include="..\..\..\..\modules\juce_core\threads\juce_WaitableEvent.cpp">\r
+ <Filter>JUCE Modules\juce_core\threads</Filter>\r
+ </ClCompile>\r
<ClCompile Include="..\..\..\..\modules\juce_core\time\juce_PerformanceCounter.cpp">\r
<Filter>JUCE Modules\juce_core\time</Filter>\r
</ClCompile>\r
<ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_RuntimePermissions.h">\r
<Filter>JUCE Modules\juce_core\misc</Filter>\r
</ClInclude>\r
- <ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_StdFunctionCompat.h">\r
- <Filter>JUCE Modules\juce_core\misc</Filter>\r
- </ClInclude>\r
<ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_Uuid.h">\r
<Filter>JUCE Modules\juce_core\misc</Filter>\r
</ClInclude>\r
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+</dict>
+</plist>
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
-</dict>
-</plist>
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;
\r
#define JUCE_USE_DARK_SPLASH_SCREEN 1\r
\r
-#define JUCE_PROJUCER_VERSION 0x50405\r
+#define JUCE_PROJUCER_VERSION 0x50406\r
\r
//==============================================================================\r
#define JUCE_MODULE_AVAILABLE_juce_audio_basics 1\r
//==============================================================================\r
// juce_events flags:\r
\r
-#ifndef JUCE_EXECUTE_APP_SUSPEND_ON_IOS_BACKGROUND_TASK\r
- //#define JUCE_EXECUTE_APP_SUSPEND_ON_IOS_BACKGROUND_TASK 0\r
+#ifndef JUCE_EXECUTE_APP_SUSPEND_ON_BACKGROUND_TASK\r
+ //#define JUCE_EXECUTE_APP_SUSPEND_ON_BACKGROUND_TASK 0\r
#endif\r
\r
//==============================================================================\r
==============================================================================\r
*/\r
\r
-#include "../JuceLibraryCode/JuceHeader.h"\r
+#include <JuceHeader.h>\r
#include "UI/MainHostWindow.h"\r
#include "Plugins/InternalPlugins.h"\r
\r
==============================================================================\r
*/\r
\r
-#include "../JuceLibraryCode/JuceHeader.h"\r
+#include <JuceHeader.h>\r
#include "../UI/GraphEditorPanel.h"\r
#include "InternalPlugins.h"\r
#include "../UI/MainHostWindow.h"\r
==============================================================================\r
*/\r
\r
-#include "../JuceLibraryCode/JuceHeader.h"\r
+#include <JuceHeader.h>\r
#include "InternalPlugins.h"\r
#include "PluginGraph.h"\r
\r
AudioProcessorGraph::AudioGraphIOProcessor p (AudioProcessorGraph::AudioGraphIOProcessor::midiInputNode);\r
p.fillInPluginDescription (midiInDesc);\r
}\r
+\r
+ {\r
+ AudioProcessorGraph::AudioGraphIOProcessor p (AudioProcessorGraph::AudioGraphIOProcessor::midiOutputNode);\r
+ p.fillInPluginDescription (midiOutDesc);\r
+ }\r
}\r
\r
std::unique_ptr<AudioPluginInstance> InternalPluginFormat::createInstance (const String& name)\r
if (name == audioOutDesc.name) return std::make_unique<AudioProcessorGraph::AudioGraphIOProcessor> (AudioProcessorGraph::AudioGraphIOProcessor::audioOutputNode);\r
if (name == audioInDesc.name) return std::make_unique<AudioProcessorGraph::AudioGraphIOProcessor> (AudioProcessorGraph::AudioGraphIOProcessor::audioInputNode);\r
if (name == midiInDesc.name) return std::make_unique<AudioProcessorGraph::AudioGraphIOProcessor> (AudioProcessorGraph::AudioGraphIOProcessor::midiInputNode);\r
+ if (name == midiOutDesc.name) return std::make_unique<AudioProcessorGraph::AudioGraphIOProcessor> (AudioProcessorGraph::AudioGraphIOProcessor::midiOutputNode);\r
\r
if (name == SineWaveSynth::getIdentifier()) return std::make_unique<SineWaveSynth> (SineWaveSynth::getPluginDescription());\r
if (name == ReverbPlugin::getIdentifier()) return std::make_unique<ReverbPlugin> (ReverbPlugin::getPluginDescription());\r
\r
void InternalPluginFormat::getAllTypes (Array<PluginDescription>& results)\r
{\r
- results.add (audioInDesc, audioOutDesc, midiInDesc,\r
- SineWaveSynth::getPluginDescription(),\r
- ReverbPlugin::getPluginDescription());\r
+ results.add (audioInDesc, audioOutDesc, midiInDesc, midiOutDesc,\r
+ SineWaveSynth::getPluginDescription(), ReverbPlugin::getPluginDescription());\r
}\r
~InternalPluginFormat() override {}\r
\r
//==============================================================================\r
- PluginDescription audioInDesc, audioOutDesc, midiInDesc;\r
+ PluginDescription audioInDesc, audioOutDesc, midiInDesc, midiOutDesc;\r
void getAllTypes (Array<PluginDescription>&);\r
\r
//==============================================================================\r
==============================================================================\r
*/\r
\r
-#include "../JuceLibraryCode/JuceHeader.h"\r
+#include <JuceHeader.h>\r
#include "../UI/MainHostWindow.h"\r
#include "PluginGraph.h"\r
#include "InternalPlugins.h"\r
addPlugin (internalFormat.audioInDesc, { 0.5, 0.1 });\r
addPlugin (internalFormat.midiInDesc, { 0.25, 0.1 });\r
addPlugin (internalFormat.audioOutDesc, { 0.5, 0.9 });\r
+ addPlugin (internalFormat.midiOutDesc, { 0.25, 0.9 });\r
\r
- MessageManager::callAsync ([this] () {\r
+ MessageManager::callAsync ([this]\r
+ {\r
setChangedFlag (false);\r
graph.addChangeListener (this);\r
- } );\r
+ });\r
}\r
\r
Result PluginGraph::loadDocument (const File& file)\r
==============================================================================\r
*/\r
\r
-#include "../JuceLibraryCode/JuceHeader.h"\r
+#include <JuceHeader.h>\r
#include "GraphEditorPanel.h"\r
#include "../Plugins/InternalPlugins.h"\r
#include "MainHostWindow.h"\r
deviceManager.addChangeListener (graphPanel.get());\r
deviceManager.addAudioCallback (&graphPlayer);\r
deviceManager.addMidiInputDeviceCallback ({}, &graphPlayer.getMidiMessageCollector());\r
+ deviceManager.addChangeListener (this);\r
}\r
\r
void GraphDocumentComponent::init()\r
{\r
+ updateMidiOutput();\r
+\r
graphPanel.reset (new GraphEditorPanel (*graph));\r
addAndMakeVisible (graphPanel.get());\r
graphPlayer.setProcessor (&graph->graph);\r
\r
GraphDocumentComponent::~GraphDocumentComponent()\r
{\r
+ if (midiOutput != nullptr)\r
+ midiOutput->stopBackgroundThread();\r
+\r
releaseGraph();\r
\r
keyState.removeListener (&graphPlayer.getMidiMessageCollector());\r
{\r
return graphPanel->graph.closeAnyOpenPluginWindows();\r
}\r
+\r
+void GraphDocumentComponent::changeListenerCallback (ChangeBroadcaster*)\r
+{\r
+ updateMidiOutput();\r
+}\r
+\r
+void GraphDocumentComponent::updateMidiOutput()\r
+{\r
+ auto* defaultMidiOutput = deviceManager.getDefaultMidiOutput();\r
+\r
+ if (midiOutput != defaultMidiOutput)\r
+ {\r
+ midiOutput = defaultMidiOutput;\r
+\r
+ if (midiOutput != nullptr)\r
+ midiOutput->startBackgroundThread();\r
+\r
+ graphPlayer.setMidiOutput (midiOutput);\r
+ }\r
+}\r
*/\r
class GraphDocumentComponent : public Component,\r
public DragAndDropTarget,\r
- public DragAndDropContainer\r
+ public DragAndDropContainer,\r
+ private ChangeListener\r
{\r
public:\r
GraphDocumentComponent (AudioPluginFormatManager& formatManager,\r
\r
AudioProcessorPlayer graphPlayer;\r
MidiKeyboardState keyState;\r
+ MidiOutput* midiOutput = nullptr;\r
\r
struct TooltipBar;\r
std::unique_ptr<TooltipBar> statusBar;\r
SidePanel* lastOpenedSidePanel = nullptr;\r
\r
//==============================================================================\r
+ void changeListenerCallback (ChangeBroadcaster*) override;\r
+\r
void init();\r
void checkAvailableWidth();\r
+ void updateMidiOutput();\r
\r
//==============================================================================\r
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (GraphDocumentComponent)\r
==============================================================================\r
*/\r
\r
-#include "../JuceLibraryCode/JuceHeader.h"\r
+#include <JuceHeader.h>\r
#include "MainHostWindow.h"\r
#include "../Plugins/InternalPlugins.h"\r
\r
class PluginGraph;\r
\r
/**\r
- A window that shows a log of parameter change messagse sent by the plugin.\r
+ A window that shows a log of parameter change messages sent by the plugin.\r
*/\r
class PluginDebugWindow : public AudioProcessorEditor,\r
public AudioProcessorParameter::Listener,\r
<?xml version="1.0" encoding="UTF-8"?>\r
\r
<JUCERPROJECT id="3t6YqETY1" name="BinaryBuilder" projectType="consoleapp"\r
- juceFolder="../../../juce" jucerVersion="5.4.5" bundleIdentifier="com.roli.binarybuilder"\r
+ juceFolder="../../../juce" jucerVersion="5.4.6" bundleIdentifier="com.roli.binarybuilder"\r
displaySplashScreen="0" reportAppUsage="0" companyName="ROLI Ltd."\r
companyCopyright="ROLI Ltd.">\r
<EXPORTFORMATS>\r
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
-</dict>
-</plist>
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;
GCC_WARN_UNUSED_VARIABLE = YES;
ONLY_ACTIVE_ARCH = YES;
PRODUCT_NAME = "BinaryBuilder";
+ SDKROOT = macosx;
WARNING_CFLAGS = "-Wreorder";
ZERO_LINK = NO;
};
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
PRODUCT_NAME = "BinaryBuilder";
+ SDKROOT = macosx;
WARNING_CFLAGS = "-Wreorder";
ZERO_LINK = NO;
};
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+</dict>
+</plist>
<ClCompile Include="..\..\..\..\modules\juce_core\misc\juce_RuntimePermissions.cpp">\r
<ExcludedFromBuild>true</ExcludedFromBuild>\r
</ClCompile>\r
- <ClCompile Include="..\..\..\..\modules\juce_core\misc\juce_StdFunctionCompat.cpp">\r
- <ExcludedFromBuild>true</ExcludedFromBuild>\r
- </ClCompile>\r
<ClCompile Include="..\..\..\..\modules\juce_core\misc\juce_Uuid.cpp">\r
<ExcludedFromBuild>true</ExcludedFromBuild>\r
</ClCompile>\r
<ClCompile Include="..\..\..\..\modules\juce_core\threads\juce_TimeSliceThread.cpp">\r
<ExcludedFromBuild>true</ExcludedFromBuild>\r
</ClCompile>\r
+ <ClCompile Include="..\..\..\..\modules\juce_core\threads\juce_WaitableEvent.cpp">\r
+ <ExcludedFromBuild>true</ExcludedFromBuild>\r
+ </ClCompile>\r
<ClCompile Include="..\..\..\..\modules\juce_core\time\juce_PerformanceCounter.cpp">\r
<ExcludedFromBuild>true</ExcludedFromBuild>\r
</ClCompile>\r
<ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_ConsoleApplication.h"/>\r
<ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_Result.h"/>\r
<ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_RuntimePermissions.h"/>\r
- <ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_StdFunctionCompat.h"/>\r
<ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_Uuid.h"/>\r
<ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_WindowsRegistry.h"/>\r
<ClInclude Include="..\..\..\..\modules\juce_core\native\juce_android_JNIHelpers.h"/>\r
<ClCompile Include="..\..\..\..\modules\juce_core\misc\juce_RuntimePermissions.cpp">\r
<Filter>JUCE Modules\juce_core\misc</Filter>\r
</ClCompile>\r
- <ClCompile Include="..\..\..\..\modules\juce_core\misc\juce_StdFunctionCompat.cpp">\r
- <Filter>JUCE Modules\juce_core\misc</Filter>\r
- </ClCompile>\r
<ClCompile Include="..\..\..\..\modules\juce_core\misc\juce_Uuid.cpp">\r
<Filter>JUCE Modules\juce_core\misc</Filter>\r
</ClCompile>\r
<ClCompile Include="..\..\..\..\modules\juce_core\threads\juce_TimeSliceThread.cpp">\r
<Filter>JUCE Modules\juce_core\threads</Filter>\r
</ClCompile>\r
+ <ClCompile Include="..\..\..\..\modules\juce_core\threads\juce_WaitableEvent.cpp">\r
+ <Filter>JUCE Modules\juce_core\threads</Filter>\r
+ </ClCompile>\r
<ClCompile Include="..\..\..\..\modules\juce_core\time\juce_PerformanceCounter.cpp">\r
<Filter>JUCE Modules\juce_core\time</Filter>\r
</ClCompile>\r
<ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_RuntimePermissions.h">\r
<Filter>JUCE Modules\juce_core\misc</Filter>\r
</ClInclude>\r
- <ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_StdFunctionCompat.h">\r
- <Filter>JUCE Modules\juce_core\misc</Filter>\r
- </ClInclude>\r
<ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_Uuid.h">\r
<Filter>JUCE Modules\juce_core\misc</Filter>\r
</ClInclude>\r
\r
#define JUCE_USE_DARK_SPLASH_SCREEN 1\r
\r
-#define JUCE_PROJUCER_VERSION 0x50405\r
+#define JUCE_PROJUCER_VERSION 0x50406\r
\r
//==============================================================================\r
#define JUCE_MODULE_AVAILABLE_juce_core 1\r
==============================================================================\r
*/\r
\r
-#include "../JuceLibraryCode/JuceHeader.h"\r
+#include <JuceHeader.h>\r
\r
\r
//==============================================================================\r
"../../../../../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"
"../../../../../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"
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)
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)
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
<uses-permission android:name="android.permission.BLUETOOTH"/>
+ <uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-feature android:glEsVersion="0x00020000" android:required="true"/>
<application android:label="@string/app_name" android:name="com.roli.juce.JuceApp" android:icon="@drawable/icon" android:hardwareAccelerated="false">
jcenter()
}
dependencies {
- classpath 'com.android.tools.build:gradle:3.2.1'
+ classpath 'com.android.tools.build:gradle:3.5.3'
}
}
-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
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+</dict>
+</plist>
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
-</dict>
-</plist>
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;
GCC_WARN_UNUSED_VARIABLE = YES;
ONLY_ACTIVE_ARCH = YES;
PRODUCT_NAME = "JUCE Network Graphics Demo";
+ SDKROOT = macosx;
WARNING_CFLAGS = "-Wreorder";
ZERO_LINK = NO;
};
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
PRODUCT_NAME = "JUCE Network Graphics Demo";
+ SDKROOT = macosx;
WARNING_CFLAGS = "-Wreorder";
ZERO_LINK = NO;
};
<ClCompile Include="..\..\..\..\modules\juce_core\misc\juce_RuntimePermissions.cpp">\r
<ExcludedFromBuild>true</ExcludedFromBuild>\r
</ClCompile>\r
- <ClCompile Include="..\..\..\..\modules\juce_core\misc\juce_StdFunctionCompat.cpp">\r
- <ExcludedFromBuild>true</ExcludedFromBuild>\r
- </ClCompile>\r
<ClCompile Include="..\..\..\..\modules\juce_core\misc\juce_Uuid.cpp">\r
<ExcludedFromBuild>true</ExcludedFromBuild>\r
</ClCompile>\r
<ClCompile Include="..\..\..\..\modules\juce_core\threads\juce_TimeSliceThread.cpp">\r
<ExcludedFromBuild>true</ExcludedFromBuild>\r
</ClCompile>\r
+ <ClCompile Include="..\..\..\..\modules\juce_core\threads\juce_WaitableEvent.cpp">\r
+ <ExcludedFromBuild>true</ExcludedFromBuild>\r
+ </ClCompile>\r
<ClCompile Include="..\..\..\..\modules\juce_core\time\juce_PerformanceCounter.cpp">\r
<ExcludedFromBuild>true</ExcludedFromBuild>\r
</ClCompile>\r
<ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_ConsoleApplication.h"/>\r
<ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_Result.h"/>\r
<ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_RuntimePermissions.h"/>\r
- <ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_StdFunctionCompat.h"/>\r
<ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_Uuid.h"/>\r
<ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_WindowsRegistry.h"/>\r
<ClInclude Include="..\..\..\..\modules\juce_core\native\juce_android_JNIHelpers.h"/>\r
<ClCompile Include="..\..\..\..\modules\juce_core\misc\juce_RuntimePermissions.cpp">\r
<Filter>JUCE Modules\juce_core\misc</Filter>\r
</ClCompile>\r
- <ClCompile Include="..\..\..\..\modules\juce_core\misc\juce_StdFunctionCompat.cpp">\r
- <Filter>JUCE Modules\juce_core\misc</Filter>\r
- </ClCompile>\r
<ClCompile Include="..\..\..\..\modules\juce_core\misc\juce_Uuid.cpp">\r
<Filter>JUCE Modules\juce_core\misc</Filter>\r
</ClCompile>\r
<ClCompile Include="..\..\..\..\modules\juce_core\threads\juce_TimeSliceThread.cpp">\r
<Filter>JUCE Modules\juce_core\threads</Filter>\r
</ClCompile>\r
+ <ClCompile Include="..\..\..\..\modules\juce_core\threads\juce_WaitableEvent.cpp">\r
+ <Filter>JUCE Modules\juce_core\threads</Filter>\r
+ </ClCompile>\r
<ClCompile Include="..\..\..\..\modules\juce_core\time\juce_PerformanceCounter.cpp">\r
<Filter>JUCE Modules\juce_core\time</Filter>\r
</ClCompile>\r
<ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_RuntimePermissions.h">\r
<Filter>JUCE Modules\juce_core\misc</Filter>\r
</ClInclude>\r
- <ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_StdFunctionCompat.h">\r
- <Filter>JUCE Modules\juce_core\misc</Filter>\r
- </ClInclude>\r
<ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_Uuid.h">\r
<Filter>JUCE Modules\juce_core\misc</Filter>\r
</ClInclude>\r
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+</dict>
+</plist>
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
-</dict>
-</plist>
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;
\r
#define JUCE_USE_DARK_SPLASH_SCREEN 1\r
\r
-#define JUCE_PROJUCER_VERSION 0x50405\r
+#define JUCE_PROJUCER_VERSION 0x50406\r
\r
//==============================================================================\r
#define JUCE_MODULE_AVAILABLE_juce_audio_basics 1\r
//==============================================================================\r
// juce_events flags:\r
\r
-#ifndef JUCE_EXECUTE_APP_SUSPEND_ON_IOS_BACKGROUND_TASK\r
- //#define JUCE_EXECUTE_APP_SUSPEND_ON_IOS_BACKGROUND_TASK 0\r
+#ifndef JUCE_EXECUTE_APP_SUSPEND_ON_BACKGROUND_TASK\r
+ //#define JUCE_EXECUTE_APP_SUSPEND_ON_BACKGROUND_TASK 0\r
#endif\r
\r
//==============================================================================\r
<?xml version="1.0" encoding="UTF-8"?>\r
\r
<JUCERPROJECT id="gWI5Ir" name="NetworkGraphicsDemo" projectType="guiapp" bundleIdentifier="com.juce.NetworkGraphicsDemo"\r
- jucerVersion="5.4.5" displaySplashScreen="0" reportAppUsage="0"\r
+ jucerVersion="5.4.6" displaySplashScreen="0" reportAppUsage="0"\r
companyName="ROLI Ltd." companyCopyright="ROLI Ltd.">\r
<MAINGROUP id="OT9rJ2" name="NetworkGraphicsDemo">\r
<GROUP id="{48D54E6E-37F4-B20A-E038-C63E4EDFD4D9}" name="Source">\r
==============================================================================\r
*/\r
\r
-#include "../JuceLibraryCode/JuceHeader.h"\r
+#include <JuceHeader.h>\r
\r
namespace\r
{\r
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
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
$(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 \
@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"
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+</dict>
+</plist>
<key>CFBundleSignature</key>\r
<string>????</string>\r
<key>CFBundleShortVersionString</key>\r
- <string>5.4.5</string>\r
+ <string>5.4.6</string>\r
<key>CFBundleVersion</key>\r
- <string>5.4.5</string>\r
+ <string>5.4.6</string>\r
<key>NSHumanReadableCopyright</key>\r
<string>ROLI Ltd.</string>\r
<key>NSHighResolutionCapable</key>\r
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
-</dict>
-</plist>
isa = PBXBuildFile;
fileRef = 09DE066936CF037E9709ADB1;
};
+ 8B4A593B3869815BBAC3EF93 = {
+ isa = PBXBuildFile;
+ fileRef = 7B3F7ECF6DBF8C8EE5C2CB86;
+ };
A578EAD4BB55680E8097BE0F = {
isa = PBXBuildFile;
fileRef = 80D62B907248523E6943298B;
isa = PBXBuildFile;
fileRef = 5A75806B34E4EA6598A6024A;
};
- 8B4A593B3869815BBAC3EF93 = {
- isa = PBXBuildFile;
- fileRef = 7B3F7ECF6DBF8C8EE5C2CB86;
- };
A14C2C2725DA3CA7995D2815 = {
isa = PBXBuildFile;
fileRef = 210CD22F25F2C22F9CEEB025;
isa = PBXBuildFile;
fileRef = 486E8D02DAD2A0BF54A901C0;
};
+ 44AD0D81A65C5EAE3BE588FD = {
+ isa = PBXBuildFile;
+ fileRef = FF3A6A384D536E1AEF47CD54;
+ };
638C7247B6DBA67EFE46E124 = {
isa = PBXBuildFile;
fileRef = 191330B20DAC08B890656EA0;
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;
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;
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;
A6C4AE13FB409DE414094CFA,
6FD8DBC0FF42C87D8BEE2452,
00515BA4EC5A7D4DC078ED37,
+ FF3A6A384D536E1AEF47CD54,
+ C16F9F479A3A5F6DAD7647A2,
);
name = Helpers;
sourceTree = "<group>";
0FFEF043CA89142B18C79ABE = {
isa = PBXGroup;
children = (
+ 7B3F7ECF6DBF8C8EE5C2CB86,
80D62B907248523E6943298B,
5A75806B34E4EA6598A6024A,
- 7B3F7ECF6DBF8C8EE5C2CB86,
210CD22F25F2C22F9CEEB025,
D00F311BFC3C2625C457CB9B,
D1F9B0E9F5D54FE48BEB46EA,
"_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",
"_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",
GCC_WARN_UNUSED_VARIABLE = YES;
ONLY_ACTIVE_ARCH = YES;
PRODUCT_NAME = "Projucer";
+ SDKROOT = macosx;
WARNING_CFLAGS = "-Wreorder";
ZERO_LINK = NO;
};
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
PRODUCT_NAME = "Projucer";
+ SDKROOT = macosx;
WARNING_CFLAGS = "-Wreorder";
ZERO_LINK = NO;
};
8BE478303CDF061B72F219E2,
BF913199032B4CE970E82AA3,
25EF9B3FECB4C9F0F522DCAA,
+ 44AD0D81A65C5EAE3BE588FD,
638C7247B6DBA67EFE46E124,
D0E26EB54B0087C8BE3D541E,
468548FB21D264DC12321327,
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
+ 8B4A593B3869815BBAC3EF93,
A578EAD4BB55680E8097BE0F,
C1B9334AE849F93FB3C56B34,
- 8B4A593B3869815BBAC3EF93,
A14C2C2725DA3CA7995D2815,
1E76E36772355E2A43CF4961,
241F29FCBB7A17BB44A0B10C,
<Optimization>Disabled</Optimization>\r
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\r
<AdditionalIncludeDirectories>..\..\JuceLibraryCode;..\..\..\..\modules;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
- <PreprocessorDefinitions>_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)</PreprocessorDefinitions>\r
+ <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)</PreprocessorDefinitions>\r
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>\r
<RuntimeTypeInfo>true</RuntimeTypeInfo>\r
<PrecompiledHeader/>\r
<ClCompile>\r
<Optimization>Full</Optimization>\r
<AdditionalIncludeDirectories>..\..\JuceLibraryCode;..\..\..\..\modules;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
- <PreprocessorDefinitions>_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)</PreprocessorDefinitions>\r
+ <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)</PreprocessorDefinitions>\r
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>\r
<RuntimeTypeInfo>true</RuntimeTypeInfo>\r
<PrecompiledHeader/>\r
<ClCompile Include="..\..\Source\Utility\Helpers\jucer_CodeHelpers.cpp"/>\r
<ClCompile Include="..\..\Source\Utility\Helpers\jucer_FileHelpers.cpp"/>\r
<ClCompile Include="..\..\Source\Utility\Helpers\jucer_MiscUtilities.cpp"/>\r
+ <ClCompile Include="..\..\Source\Utility\Helpers\jucer_VersionInfo.cpp"/>\r
<ClCompile Include="..\..\Source\Utility\PIPs\jucer_PIPGenerator.cpp"/>\r
<ClCompile Include="..\..\Source\Utility\UI\jucer_Icons.cpp"/>\r
<ClCompile Include="..\..\Source\Utility\UI\jucer_JucerTreeViewBase.cpp"/>\r
<ClCompile Include="..\..\..\..\modules\juce_core\misc\juce_RuntimePermissions.cpp">\r
<ExcludedFromBuild>true</ExcludedFromBuild>\r
</ClCompile>\r
- <ClCompile Include="..\..\..\..\modules\juce_core\misc\juce_StdFunctionCompat.cpp">\r
- <ExcludedFromBuild>true</ExcludedFromBuild>\r
- </ClCompile>\r
<ClCompile Include="..\..\..\..\modules\juce_core\misc\juce_Uuid.cpp">\r
<ExcludedFromBuild>true</ExcludedFromBuild>\r
</ClCompile>\r
<ClCompile Include="..\..\..\..\modules\juce_core\threads\juce_TimeSliceThread.cpp">\r
<ExcludedFromBuild>true</ExcludedFromBuild>\r
</ClCompile>\r
+ <ClCompile Include="..\..\..\..\modules\juce_core\threads\juce_WaitableEvent.cpp">\r
+ <ExcludedFromBuild>true</ExcludedFromBuild>\r
+ </ClCompile>\r
<ClCompile Include="..\..\..\..\modules\juce_core\time\juce_PerformanceCounter.cpp">\r
<ExcludedFromBuild>true</ExcludedFromBuild>\r
</ClCompile>\r
<ClInclude Include="..\..\Source\Utility\Helpers\jucer_RelativePath.h"/>\r
<ClInclude Include="..\..\Source\Utility\Helpers\jucer_TranslationHelpers.h"/>\r
<ClInclude Include="..\..\Source\Utility\Helpers\jucer_ValueSourceHelpers.h"/>\r
+ <ClInclude Include="..\..\Source\Utility\Helpers\jucer_VersionInfo.h"/>\r
<ClInclude Include="..\..\Source\Utility\PIPs\jucer_PIPGenerator.h"/>\r
<ClInclude Include="..\..\Source\Utility\UI\PropertyComponents\jucer_ColourPropertyComponent.h"/>\r
<ClInclude Include="..\..\Source\Utility\UI\PropertyComponents\jucer_FilePathPropertyComponent.h"/>\r
<ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_ConsoleApplication.h"/>\r
<ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_Result.h"/>\r
<ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_RuntimePermissions.h"/>\r
- <ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_StdFunctionCompat.h"/>\r
<ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_Uuid.h"/>\r
<ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_WindowsRegistry.h"/>\r
<ClInclude Include="..\..\..\..\modules\juce_core\native\juce_android_JNIHelpers.h"/>\r
<ClCompile Include="..\..\Source\Utility\Helpers\jucer_MiscUtilities.cpp">\r
<Filter>Projucer\Utility\Helpers</Filter>\r
</ClCompile>\r
+ <ClCompile Include="..\..\Source\Utility\Helpers\jucer_VersionInfo.cpp">\r
+ <Filter>Projucer\Utility\Helpers</Filter>\r
+ </ClCompile>\r
<ClCompile Include="..\..\Source\Utility\PIPs\jucer_PIPGenerator.cpp">\r
<Filter>Projucer\Utility\PIPs</Filter>\r
</ClCompile>\r
<ClCompile Include="..\..\..\..\modules\juce_core\misc\juce_RuntimePermissions.cpp">\r
<Filter>JUCE Modules\juce_core\misc</Filter>\r
</ClCompile>\r
- <ClCompile Include="..\..\..\..\modules\juce_core\misc\juce_StdFunctionCompat.cpp">\r
- <Filter>JUCE Modules\juce_core\misc</Filter>\r
- </ClCompile>\r
<ClCompile Include="..\..\..\..\modules\juce_core\misc\juce_Uuid.cpp">\r
<Filter>JUCE Modules\juce_core\misc</Filter>\r
</ClCompile>\r
<ClCompile Include="..\..\..\..\modules\juce_core\threads\juce_TimeSliceThread.cpp">\r
<Filter>JUCE Modules\juce_core\threads</Filter>\r
</ClCompile>\r
+ <ClCompile Include="..\..\..\..\modules\juce_core\threads\juce_WaitableEvent.cpp">\r
+ <Filter>JUCE Modules\juce_core\threads</Filter>\r
+ </ClCompile>\r
<ClCompile Include="..\..\..\..\modules\juce_core\time\juce_PerformanceCounter.cpp">\r
<Filter>JUCE Modules\juce_core\time</Filter>\r
</ClCompile>\r
<ClInclude Include="..\..\Source\Utility\Helpers\jucer_ValueSourceHelpers.h">\r
<Filter>Projucer\Utility\Helpers</Filter>\r
</ClInclude>\r
+ <ClInclude Include="..\..\Source\Utility\Helpers\jucer_VersionInfo.h">\r
+ <Filter>Projucer\Utility\Helpers</Filter>\r
+ </ClInclude>\r
<ClInclude Include="..\..\Source\Utility\PIPs\jucer_PIPGenerator.h">\r
<Filter>Projucer\Utility\PIPs</Filter>\r
</ClInclude>\r
<ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_RuntimePermissions.h">\r
<Filter>JUCE Modules\juce_core\misc</Filter>\r
</ClInclude>\r
- <ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_StdFunctionCompat.h">\r
- <Filter>JUCE Modules\juce_core\misc</Filter>\r
- </ClInclude>\r
<ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_Uuid.h">\r
<Filter>JUCE Modules\juce_core\misc</Filter>\r
</ClInclude>\r
#include <windows.h>\r
\r
VS_VERSION_INFO VERSIONINFO\r
-FILEVERSION 5,4,5,0\r
+FILEVERSION 5,4,6,0\r
BEGIN\r
BLOCK "StringFileInfo"\r
BEGIN\r
VALUE "CompanyName", "ROLI Ltd.\0"\r
VALUE "LegalCopyright", "ROLI Ltd.\0"\r
VALUE "FileDescription", "Projucer\0"\r
- VALUE "FileVersion", "5.4.5\0"\r
+ VALUE "FileVersion", "5.4.6\0"\r
VALUE "ProductName", "Projucer\0"\r
- VALUE "ProductVersion", "5.4.5\0"\r
+ VALUE "ProductVersion", "5.4.6\0"\r
END\r
END\r
\r
<Optimization>Disabled</Optimization>\r
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\r
<AdditionalIncludeDirectories>..\..\JuceLibraryCode;..\..\..\..\modules;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
- <PreprocessorDefinitions>_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)</PreprocessorDefinitions>\r
+ <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)</PreprocessorDefinitions>\r
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\r
<RuntimeTypeInfo>true</RuntimeTypeInfo>\r
<PrecompiledHeader/>\r
<ClCompile>\r
<Optimization>Full</Optimization>\r
<AdditionalIncludeDirectories>..\..\JuceLibraryCode;..\..\..\..\modules;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
- <PreprocessorDefinitions>_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)</PreprocessorDefinitions>\r
+ <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)</PreprocessorDefinitions>\r
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>\r
<RuntimeTypeInfo>true</RuntimeTypeInfo>\r
<PrecompiledHeader/>\r
<ClCompile Include="..\..\Source\Utility\Helpers\jucer_CodeHelpers.cpp"/>\r
<ClCompile Include="..\..\Source\Utility\Helpers\jucer_FileHelpers.cpp"/>\r
<ClCompile Include="..\..\Source\Utility\Helpers\jucer_MiscUtilities.cpp"/>\r
+ <ClCompile Include="..\..\Source\Utility\Helpers\jucer_VersionInfo.cpp"/>\r
<ClCompile Include="..\..\Source\Utility\PIPs\jucer_PIPGenerator.cpp"/>\r
<ClCompile Include="..\..\Source\Utility\UI\jucer_Icons.cpp"/>\r
<ClCompile Include="..\..\Source\Utility\UI\jucer_JucerTreeViewBase.cpp"/>\r
<ClCompile Include="..\..\..\..\modules\juce_core\misc\juce_RuntimePermissions.cpp">\r
<ExcludedFromBuild>true</ExcludedFromBuild>\r
</ClCompile>\r
- <ClCompile Include="..\..\..\..\modules\juce_core\misc\juce_StdFunctionCompat.cpp">\r
- <ExcludedFromBuild>true</ExcludedFromBuild>\r
- </ClCompile>\r
<ClCompile Include="..\..\..\..\modules\juce_core\misc\juce_Uuid.cpp">\r
<ExcludedFromBuild>true</ExcludedFromBuild>\r
</ClCompile>\r
<ClCompile Include="..\..\..\..\modules\juce_core\threads\juce_TimeSliceThread.cpp">\r
<ExcludedFromBuild>true</ExcludedFromBuild>\r
</ClCompile>\r
+ <ClCompile Include="..\..\..\..\modules\juce_core\threads\juce_WaitableEvent.cpp">\r
+ <ExcludedFromBuild>true</ExcludedFromBuild>\r
+ </ClCompile>\r
<ClCompile Include="..\..\..\..\modules\juce_core\time\juce_PerformanceCounter.cpp">\r
<ExcludedFromBuild>true</ExcludedFromBuild>\r
</ClCompile>\r
<ClInclude Include="..\..\Source\Utility\Helpers\jucer_RelativePath.h"/>\r
<ClInclude Include="..\..\Source\Utility\Helpers\jucer_TranslationHelpers.h"/>\r
<ClInclude Include="..\..\Source\Utility\Helpers\jucer_ValueSourceHelpers.h"/>\r
+ <ClInclude Include="..\..\Source\Utility\Helpers\jucer_VersionInfo.h"/>\r
<ClInclude Include="..\..\Source\Utility\PIPs\jucer_PIPGenerator.h"/>\r
<ClInclude Include="..\..\Source\Utility\UI\PropertyComponents\jucer_ColourPropertyComponent.h"/>\r
<ClInclude Include="..\..\Source\Utility\UI\PropertyComponents\jucer_FilePathPropertyComponent.h"/>\r
<ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_ConsoleApplication.h"/>\r
<ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_Result.h"/>\r
<ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_RuntimePermissions.h"/>\r
- <ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_StdFunctionCompat.h"/>\r
<ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_Uuid.h"/>\r
<ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_WindowsRegistry.h"/>\r
<ClInclude Include="..\..\..\..\modules\juce_core\native\juce_android_JNIHelpers.h"/>\r
<ClCompile Include="..\..\Source\Utility\Helpers\jucer_MiscUtilities.cpp">\r
<Filter>Projucer\Utility\Helpers</Filter>\r
</ClCompile>\r
+ <ClCompile Include="..\..\Source\Utility\Helpers\jucer_VersionInfo.cpp">\r
+ <Filter>Projucer\Utility\Helpers</Filter>\r
+ </ClCompile>\r
<ClCompile Include="..\..\Source\Utility\PIPs\jucer_PIPGenerator.cpp">\r
<Filter>Projucer\Utility\PIPs</Filter>\r
</ClCompile>\r
<ClCompile Include="..\..\..\..\modules\juce_core\misc\juce_RuntimePermissions.cpp">\r
<Filter>JUCE Modules\juce_core\misc</Filter>\r
</ClCompile>\r
- <ClCompile Include="..\..\..\..\modules\juce_core\misc\juce_StdFunctionCompat.cpp">\r
- <Filter>JUCE Modules\juce_core\misc</Filter>\r
- </ClCompile>\r
<ClCompile Include="..\..\..\..\modules\juce_core\misc\juce_Uuid.cpp">\r
<Filter>JUCE Modules\juce_core\misc</Filter>\r
</ClCompile>\r
<ClCompile Include="..\..\..\..\modules\juce_core\threads\juce_TimeSliceThread.cpp">\r
<Filter>JUCE Modules\juce_core\threads</Filter>\r
</ClCompile>\r
+ <ClCompile Include="..\..\..\..\modules\juce_core\threads\juce_WaitableEvent.cpp">\r
+ <Filter>JUCE Modules\juce_core\threads</Filter>\r
+ </ClCompile>\r
<ClCompile Include="..\..\..\..\modules\juce_core\time\juce_PerformanceCounter.cpp">\r
<Filter>JUCE Modules\juce_core\time</Filter>\r
</ClCompile>\r
<ClInclude Include="..\..\Source\Utility\Helpers\jucer_ValueSourceHelpers.h">\r
<Filter>Projucer\Utility\Helpers</Filter>\r
</ClInclude>\r
+ <ClInclude Include="..\..\Source\Utility\Helpers\jucer_VersionInfo.h">\r
+ <Filter>Projucer\Utility\Helpers</Filter>\r
+ </ClInclude>\r
<ClInclude Include="..\..\Source\Utility\PIPs\jucer_PIPGenerator.h">\r
<Filter>Projucer\Utility\PIPs</Filter>\r
</ClInclude>\r
<ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_RuntimePermissions.h">\r
<Filter>JUCE Modules\juce_core\misc</Filter>\r
</ClInclude>\r
- <ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_StdFunctionCompat.h">\r
- <Filter>JUCE Modules\juce_core\misc</Filter>\r
- </ClInclude>\r
<ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_Uuid.h">\r
<Filter>JUCE Modules\juce_core\misc</Filter>\r
</ClInclude>\r
#include <windows.h>\r
\r
VS_VERSION_INFO VERSIONINFO\r
-FILEVERSION 5,4,5,0\r
+FILEVERSION 5,4,6,0\r
BEGIN\r
BLOCK "StringFileInfo"\r
BEGIN\r
VALUE "CompanyName", "ROLI Ltd.\0"\r
VALUE "LegalCopyright", "ROLI Ltd.\0"\r
VALUE "FileDescription", "Projucer\0"\r
- VALUE "FileVersion", "5.4.5\0"\r
+ VALUE "FileVersion", "5.4.6\0"\r
VALUE "ProductName", "Projucer\0"\r
- VALUE "ProductVersion", "5.4.5\0"\r
+ VALUE "ProductVersion", "5.4.6\0"\r
END\r
END\r
\r
<Optimization>Disabled</Optimization>\r
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\r
<AdditionalIncludeDirectories>..\..\JuceLibraryCode;..\..\..\..\modules;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
- <PreprocessorDefinitions>_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)</PreprocessorDefinitions>\r
+ <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)</PreprocessorDefinitions>\r
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\r
<RuntimeTypeInfo>true</RuntimeTypeInfo>\r
<PrecompiledHeader/>\r
<ClCompile>\r
<Optimization>Full</Optimization>\r
<AdditionalIncludeDirectories>..\..\JuceLibraryCode;..\..\..\..\modules;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
- <PreprocessorDefinitions>_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)</PreprocessorDefinitions>\r
+ <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)</PreprocessorDefinitions>\r
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>\r
<RuntimeTypeInfo>true</RuntimeTypeInfo>\r
<PrecompiledHeader/>\r
<ClCompile Include="..\..\Source\Utility\Helpers\jucer_CodeHelpers.cpp"/>\r
<ClCompile Include="..\..\Source\Utility\Helpers\jucer_FileHelpers.cpp"/>\r
<ClCompile Include="..\..\Source\Utility\Helpers\jucer_MiscUtilities.cpp"/>\r
+ <ClCompile Include="..\..\Source\Utility\Helpers\jucer_VersionInfo.cpp"/>\r
<ClCompile Include="..\..\Source\Utility\PIPs\jucer_PIPGenerator.cpp"/>\r
<ClCompile Include="..\..\Source\Utility\UI\jucer_Icons.cpp"/>\r
<ClCompile Include="..\..\Source\Utility\UI\jucer_JucerTreeViewBase.cpp"/>\r
<ClCompile Include="..\..\..\..\modules\juce_core\misc\juce_RuntimePermissions.cpp">\r
<ExcludedFromBuild>true</ExcludedFromBuild>\r
</ClCompile>\r
- <ClCompile Include="..\..\..\..\modules\juce_core\misc\juce_StdFunctionCompat.cpp">\r
- <ExcludedFromBuild>true</ExcludedFromBuild>\r
- </ClCompile>\r
<ClCompile Include="..\..\..\..\modules\juce_core\misc\juce_Uuid.cpp">\r
<ExcludedFromBuild>true</ExcludedFromBuild>\r
</ClCompile>\r
<ClCompile Include="..\..\..\..\modules\juce_core\threads\juce_TimeSliceThread.cpp">\r
<ExcludedFromBuild>true</ExcludedFromBuild>\r
</ClCompile>\r
+ <ClCompile Include="..\..\..\..\modules\juce_core\threads\juce_WaitableEvent.cpp">\r
+ <ExcludedFromBuild>true</ExcludedFromBuild>\r
+ </ClCompile>\r
<ClCompile Include="..\..\..\..\modules\juce_core\time\juce_PerformanceCounter.cpp">\r
<ExcludedFromBuild>true</ExcludedFromBuild>\r
</ClCompile>\r
<ClInclude Include="..\..\Source\Utility\Helpers\jucer_RelativePath.h"/>\r
<ClInclude Include="..\..\Source\Utility\Helpers\jucer_TranslationHelpers.h"/>\r
<ClInclude Include="..\..\Source\Utility\Helpers\jucer_ValueSourceHelpers.h"/>\r
+ <ClInclude Include="..\..\Source\Utility\Helpers\jucer_VersionInfo.h"/>\r
<ClInclude Include="..\..\Source\Utility\PIPs\jucer_PIPGenerator.h"/>\r
<ClInclude Include="..\..\Source\Utility\UI\PropertyComponents\jucer_ColourPropertyComponent.h"/>\r
<ClInclude Include="..\..\Source\Utility\UI\PropertyComponents\jucer_FilePathPropertyComponent.h"/>\r
<ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_ConsoleApplication.h"/>\r
<ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_Result.h"/>\r
<ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_RuntimePermissions.h"/>\r
- <ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_StdFunctionCompat.h"/>\r
<ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_Uuid.h"/>\r
<ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_WindowsRegistry.h"/>\r
<ClInclude Include="..\..\..\..\modules\juce_core\native\juce_android_JNIHelpers.h"/>\r
<ClCompile Include="..\..\Source\Utility\Helpers\jucer_MiscUtilities.cpp">\r
<Filter>Projucer\Utility\Helpers</Filter>\r
</ClCompile>\r
+ <ClCompile Include="..\..\Source\Utility\Helpers\jucer_VersionInfo.cpp">\r
+ <Filter>Projucer\Utility\Helpers</Filter>\r
+ </ClCompile>\r
<ClCompile Include="..\..\Source\Utility\PIPs\jucer_PIPGenerator.cpp">\r
<Filter>Projucer\Utility\PIPs</Filter>\r
</ClCompile>\r
<ClCompile Include="..\..\..\..\modules\juce_core\misc\juce_RuntimePermissions.cpp">\r
<Filter>JUCE Modules\juce_core\misc</Filter>\r
</ClCompile>\r
- <ClCompile Include="..\..\..\..\modules\juce_core\misc\juce_StdFunctionCompat.cpp">\r
- <Filter>JUCE Modules\juce_core\misc</Filter>\r
- </ClCompile>\r
<ClCompile Include="..\..\..\..\modules\juce_core\misc\juce_Uuid.cpp">\r
<Filter>JUCE Modules\juce_core\misc</Filter>\r
</ClCompile>\r
<ClCompile Include="..\..\..\..\modules\juce_core\threads\juce_TimeSliceThread.cpp">\r
<Filter>JUCE Modules\juce_core\threads</Filter>\r
</ClCompile>\r
+ <ClCompile Include="..\..\..\..\modules\juce_core\threads\juce_WaitableEvent.cpp">\r
+ <Filter>JUCE Modules\juce_core\threads</Filter>\r
+ </ClCompile>\r
<ClCompile Include="..\..\..\..\modules\juce_core\time\juce_PerformanceCounter.cpp">\r
<Filter>JUCE Modules\juce_core\time</Filter>\r
</ClCompile>\r
<ClInclude Include="..\..\Source\Utility\Helpers\jucer_ValueSourceHelpers.h">\r
<Filter>Projucer\Utility\Helpers</Filter>\r
</ClInclude>\r
+ <ClInclude Include="..\..\Source\Utility\Helpers\jucer_VersionInfo.h">\r
+ <Filter>Projucer\Utility\Helpers</Filter>\r
+ </ClInclude>\r
<ClInclude Include="..\..\Source\Utility\PIPs\jucer_PIPGenerator.h">\r
<Filter>Projucer\Utility\PIPs</Filter>\r
</ClInclude>\r
<ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_RuntimePermissions.h">\r
<Filter>JUCE Modules\juce_core\misc</Filter>\r
</ClInclude>\r
- <ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_StdFunctionCompat.h">\r
- <Filter>JUCE Modules\juce_core\misc</Filter>\r
- </ClInclude>\r
<ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_Uuid.h">\r
<Filter>JUCE Modules\juce_core\misc</Filter>\r
</ClInclude>\r
#include <windows.h>\r
\r
VS_VERSION_INFO VERSIONINFO\r
-FILEVERSION 5,4,5,0\r
+FILEVERSION 5,4,6,0\r
BEGIN\r
BLOCK "StringFileInfo"\r
BEGIN\r
VALUE "CompanyName", "ROLI Ltd.\0"\r
VALUE "LegalCopyright", "ROLI Ltd.\0"\r
VALUE "FileDescription", "Projucer\0"\r
- VALUE "FileVersion", "5.4.5\0"\r
+ VALUE "FileVersion", "5.4.6\0"\r
VALUE "ProductName", "Projucer\0"\r
- VALUE "ProductVersion", "5.4.5\0"\r
+ VALUE "ProductVersion", "5.4.6\0"\r
END\r
END\r
\r
\r
#define JUCE_USE_DARK_SPLASH_SCREEN 1\r
\r
-#define JUCE_PROJUCER_VERSION 0x50405\r
+#define JUCE_PROJUCER_VERSION 0x50406\r
\r
//==============================================================================\r
#define JUCE_MODULE_AVAILABLE_juce_analytics 1\r
//==============================================================================\r
// juce_events flags:\r
\r
-#ifndef JUCE_EXECUTE_APP_SUSPEND_ON_IOS_BACKGROUND_TASK\r
- //#define JUCE_EXECUTE_APP_SUSPEND_ON_IOS_BACKGROUND_TASK 0\r
+#ifndef JUCE_EXECUTE_APP_SUSPEND_ON_BACKGROUND_TASK\r
+ //#define JUCE_EXECUTE_APP_SUSPEND_ON_BACKGROUND_TASK 0\r
#endif\r
\r
//==============================================================================\r
"#pragma once\r\n"\r
"\r\n"\r
"//[Headers] -- You can add your own extra header files here --\r\n"\r
-"%%include_juce_header%%\r\n"\r
+"%%include_juce%%\r\n"\r
"//[/Headers]\r\n"\r
"\r\n"\r
"%%include_files_h%%\r\n"\r
"public:\r\n"\r
" //==============================================================================\r\n"\r
" %%class_name%% (%%constructor_params%%);\r\n"\r
-" ~%%class_name%%();\r\n"\r
+" ~%%class_name%%() override;\r\n"\r
"\r\n"\r
" //==============================================================================\r\n"\r
" //[UserMethods] -- You can add your own custom methods in this section.\r\n"\r
" ==============================================================================\r\n"\r
"*/\r\n"\r
"\r\n"\r
-"#include \"../JuceLibraryCode/JuceHeader.h\"\r\n"\r
+"%%include_juce%%\r\n"\r
"#include \"%%filename%%\"\r\n"\r
"\r\n"\r
"%%component_begin%%\r\n"\r
case 0x51b49ac5: numBytes = 6036; return jucer_AudioPluginFilterTemplate_cpp;\r
case 0x488afa0a: numBytes = 2272; return jucer_AudioPluginFilterTemplate_h;\r
case 0xabad7041: numBytes = 2126; return jucer_ComponentTemplate_cpp;\r
- case 0xfc72fe86: numBytes = 2042; return jucer_ComponentTemplate_h;\r
+ case 0xfc72fe86: numBytes = 2044; return jucer_ComponentTemplate_h;\r
case 0x1657b643: numBytes = 1693; return jucer_ContentCompSimpleTemplate_h;\r
case 0x0b66646c: numBytes = 1190; return jucer_ContentCompTemplate_cpp;\r
case 0x6fa10171: numBytes = 1071; return jucer_ContentCompTemplate_h;\r
case 0x7fbac252: numBytes = 1665; return jucer_OpenGLComponentTemplate_cpp;\r
case 0x491fa0d7: numBytes = 1263; return jucer_OpenGLComponentTemplate_h;\r
case 0xbc050edc: numBytes = 4926; return jucer_PIPAudioProcessorTemplate_h;\r
- case 0xf4ca9e9a: numBytes = 2447; return jucer_PIPMain_cpp;\r
+ case 0xf4ca9e9a: numBytes = 2421; return jucer_PIPMain_cpp;\r
case 0x0b16e320: numBytes = 517; return jucer_PIPTemplate_h;\r
case 0xcd472557: numBytes = 6433; return jucer_UnityPluginGUIScript_cs;\r
case 0x763d39dc: numBytes = 1050; return colourscheme_dark_xml;\r
const int jucer_ComponentTemplate_cppSize = 2126;\r
\r
extern const char* jucer_ComponentTemplate_h;\r
- const int jucer_ComponentTemplate_hSize = 2042;\r
+ const int jucer_ComponentTemplate_hSize = 2044;\r
\r
extern const char* jucer_ContentCompSimpleTemplate_h;\r
const int jucer_ContentCompSimpleTemplate_hSize = 1693;\r
const int jucer_PIPAudioProcessorTemplate_hSize = 4926;\r
\r
extern const char* jucer_PIPMain_cpp;\r
- const int jucer_PIPMain_cppSize = 2447;\r
+ const int jucer_PIPMain_cppSize = 2421;\r
\r
extern const char* jucer_PIPTemplate_h;\r
const int jucer_PIPTemplate_hSize = 517;\r
{\r
const char* const projectName = "Projucer";\r
const char* const companyName = "ROLI Ltd.";\r
- const char* const versionString = "5.4.5";\r
- const int versionNumber = 0x50405;\r
+ const char* const versionString = "5.4.6";\r
+ const int versionNumber = 0x50406;\r
}\r
#endif\r
<?xml version="1.0" encoding="UTF-8"?>\r
\r
<JUCERPROJECT id="M70qfTRRk" name="Projucer" projectType="guiapp" juceFolder="../../juce"\r
- jucerVersion="5.4.5" version="5.4.5" bundleIdentifier="com.juce.theprojucer"\r
+ jucerVersion="5.4.6" version="5.4.6" bundleIdentifier="com.juce.theprojucer"\r
splashScreenColour="Dark" displaySplashScreen="0" reportAppUsage="0"\r
companyName="ROLI Ltd." companyCopyright="ROLI Ltd." cppLanguageStandard="11">\r
<EXPORTFORMATS>\r
file="Source/Utility/Helpers/jucer_TranslationHelpers.h"/>\r
<FILE id="EuC4K4" name="jucer_ValueSourceHelpers.h" compile="0" resource="0"\r
file="Source/Utility/Helpers/jucer_ValueSourceHelpers.h"/>\r
+ <FILE id="BPCoKV" name="jucer_VersionInfo.cpp" compile="1" resource="0"\r
+ file="Source/Utility/Helpers/jucer_VersionInfo.cpp"/>\r
+ <FILE id="TnBQtv" name="jucer_VersionInfo.h" compile="0" resource="0"\r
+ file="Source/Utility/Helpers/jucer_VersionInfo.h"/>\r
</GROUP>\r
<GROUP id="{A07C4A97-0855-5346-CAF2-A005580B6773}" name="PIPs">\r
<FILE id="joAnDa" name="jucer_PIPGenerator.cpp" compile="1" resource="0"\r
builder.add (new FilePathPropertyComponent (juceModulePathValue, "JUCE Modules", true, isThisOS),\r
String ("This should be the path to the folder containing the JUCE modules that you wish to use, typically the \"modules\" directory of your JUCE folder.")\r
+ (isThisOS ? " Use the button below to re-scan a new path." : ""));\r
- builder.add (new FilePathPropertyComponent (userModulePathValue, "User Modules", true, isThisOS, {}, {}, true),\r
+ builder.add (new FilePathPropertyComponent (userModulePathValue, "User Modules", true, isThisOS),\r
String ("A path to a folder containing any custom modules that you wish to use.")\r
+ (isThisOS ? " Use the button below to re-scan new paths." : ""));\r
\r
void ProjucerApplication::createNewProject()\r
{\r
auto* mw = mainWindowList.getOrCreateEmptyWindow();\r
+ jassert (mw != nullptr);\r
+\r
mw->showStartPage();\r
\r
- mainWindowList.avoidSuperimposedWindows (mw);\r
+ mainWindowList.checkWindowBounds (*mw);\r
}\r
\r
void ProjucerApplication::createNewProjectFromClipboard()\r
//==============================================================================\r
void LatestVersionCheckerAndUpdater::run()\r
{\r
- queryUpdateServer();\r
+ auto info = VersionInfo::fetchLatestFromUpdateServer();\r
\r
- if (! threadShouldExit())\r
- MessageManager::callAsync ([this] { processResult(); });\r
-}\r
-\r
-//==============================================================================\r
-String getOSString()\r
-{\r
- #if JUCE_MAC\r
- return "OSX";\r
- #elif JUCE_WINDOWS\r
- return "Windows";\r
- #elif JUCE_LINUX\r
- return "Linux";\r
- #else\r
- jassertfalse;\r
- return "Unknown";\r
- #endif\r
-}\r
-\r
-namespace VersionHelpers\r
-{\r
- String formatProductVersion (int versionNum)\r
+ if (info == nullptr)\r
{\r
- int major = (versionNum & 0xff0000) >> 16;\r
- int minor = (versionNum & 0x00ff00) >> 8;\r
- int build = (versionNum & 0x0000ff) >> 0;\r
-\r
- return String (major) + '.' + String (minor) + '.' + String (build);\r
- }\r
+ if (showAlertWindows)\r
+ AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon,\r
+ "Update Server Communication Error",\r
+ "Failed to communicate with the JUCE update server.\n"\r
+ "Please try again in a few minutes.\n\n"\r
+ "If this problem persists you can download the latest version of JUCE from juce.com");\r
\r
- String getProductVersionString()\r
- {\r
- return formatProductVersion (ProjectInfo::versionNumber);\r
+ return;\r
}\r
\r
- bool isNewVersion (const String& current, const String& other)\r
+ if (! info->isNewerVersionThanCurrent())\r
{\r
- auto currentTokens = StringArray::fromTokens (current, ".", {});\r
- auto otherTokens = StringArray::fromTokens (other, ".", {});\r
-\r
- jassert (currentTokens.size() == 3 && otherTokens.size() == 3);\r
-\r
- if (currentTokens[0].getIntValue() == otherTokens[0].getIntValue())\r
- {\r
- if (currentTokens[1].getIntValue() == otherTokens[1].getIntValue())\r
- return currentTokens[2].getIntValue() < otherTokens[2].getIntValue();\r
-\r
- return currentTokens[1].getIntValue() < otherTokens[1].getIntValue();\r
- }\r
-\r
- return currentTokens[0].getIntValue() < otherTokens[0].getIntValue();\r
- }\r
-}\r
-\r
-void LatestVersionCheckerAndUpdater::queryUpdateServer()\r
-{\r
- StringPairArray responseHeaders;\r
-\r
- URL latestVersionURL ("https://my.roli.com/software_versions/update_to/Projucer/"\r
- + VersionHelpers::getProductVersionString() + '/' + getOSString()\r
- + "?language=" + SystemStats::getUserLanguage());\r
-\r
- std::unique_ptr<InputStream> inStream (latestVersionURL.createInputStream (false, nullptr, nullptr,\r
- "X-API-Key: 265441b-343403c-20f6932-76361d\nContent-Type: "\r
- "application/json\nAccept: application/json; version=1",\r
- 0, &responseHeaders, &statusCode, 0));\r
-\r
- if (threadShouldExit())\r
+ if (showAlertWindows)\r
+ AlertWindow::showMessageBoxAsync (AlertWindow::InfoIcon,\r
+ "No New Version Available",\r
+ "Your JUCE version is up to date.");\r
return;\r
-\r
- if (inStream.get() != nullptr && (statusCode == 303 || statusCode == 400))\r
- {\r
- if (statusCode == 303)\r
- relativeDownloadPath = responseHeaders["Location"];\r
-\r
- jassert (relativeDownloadPath.isNotEmpty());\r
-\r
- jsonReply = JSON::parse (inStream->readEntireStreamAsString());\r
- }\r
- else if (showAlertWindows)\r
- {\r
- if (statusCode == 204)\r
- AlertWindow::showMessageBoxAsync (AlertWindow::InfoIcon, "No New Version Available", "Your JUCE version is up to date.");\r
- else\r
- AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon, "Network Error", "Could not connect to the web server.\n"\r
- "Please check your internet connection and try again.");\r
}\r
-}\r
-\r
-void LatestVersionCheckerAndUpdater::processResult()\r
-{\r
- if (! jsonReply.isObject())\r
- return;\r
\r
- if (statusCode == 400)\r
+ auto osString = []\r
{\r
- auto errorObject = jsonReply.getDynamicObject()->getProperty ("error");\r
-\r
- if (errorObject.isObject())\r
+ #if JUCE_MAC\r
+ return "osx";\r
+ #elif JUCE_WINDOWS\r
+ return "windows";\r
+ #elif JUCE_LINUX\r
+ return "linux";\r
+ #else\r
+ jassertfalse;\r
+ return "Unknown";\r
+ #endif\r
+ }();\r
+\r
+ String requiredFilename ("juce-" + info->versionString + "-" + osString + ".zip");\r
+\r
+ for (auto& asset : info->assets)\r
+ {\r
+ if (asset.name == requiredFilename)\r
{\r
- auto message = errorObject.getProperty ("message", {}).toString();\r
+ auto versionString = info->versionString;\r
+ auto releaseNotes = info->releaseNotes;\r
\r
- if (message.isNotEmpty())\r
- AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon, "JUCE Updater", message);\r
+ MessageManager::callAsync ([this, versionString, releaseNotes, asset]\r
+ {\r
+ askUserAboutNewVersion (versionString, releaseNotes, asset);\r
+ });\r
+\r
+ return;\r
}\r
}\r
- else if (statusCode == 303)\r
- {\r
- askUserAboutNewVersion (jsonReply.getProperty ("version", {}).toString(),\r
- jsonReply.getProperty ("notes", {}).toString());\r
- }\r
+\r
+ if (showAlertWindows)\r
+ AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon,\r
+ "Failed to find any new downloads",\r
+ "Please try again in a few minutes.");\r
}\r
\r
//==============================================================================\r
RectanglePlacement::stretchToFit, 1.0f);\r
}\r
\r
- static std::unique_ptr<DialogWindow> launchDialog (const String& newVersion, const String& releaseNotes)\r
+ static std::unique_ptr<DialogWindow> launchDialog (const String& newVersionString,\r
+ const String& releaseNotes)\r
{\r
DialogWindow::LaunchOptions options;\r
\r
- options.dialogTitle = "Download JUCE version " + newVersion + "?";\r
+ options.dialogTitle = "Download JUCE version " + newVersionString + "?";\r
options.resizable = false;\r
\r
- auto* content = new UpdateDialog (newVersion, releaseNotes);\r
+ auto* content = new UpdateDialog (newVersionString, releaseNotes);\r
options.content.set (content, true);\r
\r
std::unique_ptr<DialogWindow> dialog (options.create());\r
DialogWindow* parentWindow = nullptr;\r
};\r
\r
-void LatestVersionCheckerAndUpdater::askUserForLocationToDownload()\r
+void LatestVersionCheckerAndUpdater::askUserForLocationToDownload (const VersionInfo::Asset& asset)\r
{\r
- FileChooser chooser ("Please select the location into which you'd like to install the new version",\r
+ FileChooser chooser ("Please select the location into which you would like to install the new version",\r
{ getAppSettings().getStoredPath (Ids::jucePath, TargetOS::getThisOS()).get() });\r
\r
if (chooser.browseForDirectory())\r
{\r
auto targetFolder = chooser.getResult();\r
\r
- if (isJUCEFolder (targetFolder))\r
+ // By default we will install into 'targetFolder/JUCE', but we should install into\r
+ // 'targetFolder' if that is an existing JUCE directory.\r
+ bool willOverwriteJuceFolder = [&targetFolder]\r
+ {\r
+ if (isJUCEFolder (targetFolder))\r
+ return true;\r
+\r
+ targetFolder = targetFolder.getChildFile ("JUCE");\r
+\r
+ return isJUCEFolder (targetFolder);\r
+ }();\r
+\r
+ auto targetFolderPath = targetFolder.getFullPathName();\r
+\r
+ if (willOverwriteJuceFolder)\r
{\r
if (targetFolder.getChildFile (".git").isDirectory())\r
{\r
AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon, "Downloading New JUCE Version",\r
- "This folder is a GIT repository!\n\nYou should use a \"git pull\" to update it to the latest version.");\r
+ targetFolderPath + "\n\nis a GIT repository!\n\nYou should use a \"git pull\" to update it to the latest version.");\r
\r
return;\r
}\r
\r
if (! AlertWindow::showOkCancelBox (AlertWindow::WarningIcon, "Overwrite Existing JUCE Folder?",\r
- String ("Do you want to overwrite the folder:\n\n" + targetFolder.getFullPathName() + "\n\n..with the latest version from juce.com?\n\n"\r
- "This will move the existing folder to " + targetFolder.getFullPathName() + "_old.")))\r
+ "Do you want to replace the folder\n\n" + targetFolderPath + "\n\nwith the latest version from juce.com?\n\n"\r
+ "This will move the existing folder to " + targetFolderPath + "_old."))\r
{\r
return;\r
}\r
}\r
- else\r
+ else if (targetFolder.exists())\r
{\r
- targetFolder = targetFolder.getChildFile ("JUCE").getNonexistentSibling();\r
+ if (! AlertWindow::showOkCancelBox (AlertWindow::WarningIcon, "Existing File Or Directory",\r
+ "Do you want to move\n\n" + targetFolderPath + "\n\nto\n\n" + targetFolderPath + "_old?"))\r
+ {\r
+ return;\r
+ }\r
}\r
\r
- downloadAndInstall (targetFolder);\r
+ downloadAndInstall (asset, targetFolder);\r
}\r
}\r
\r
-void LatestVersionCheckerAndUpdater::askUserAboutNewVersion (const String& newVersion, const String& releaseNotes)\r
+void LatestVersionCheckerAndUpdater::askUserAboutNewVersion (const String& newVersionString,\r
+ const String& releaseNotes,\r
+ const VersionInfo::Asset& asset)\r
{\r
- if (newVersion.isNotEmpty() && releaseNotes.isNotEmpty()\r
- && VersionHelpers::isNewVersion (VersionHelpers::getProductVersionString(), newVersion))\r
- {\r
- dialogWindow = UpdateDialog::launchDialog (newVersion, releaseNotes);\r
+ dialogWindow = UpdateDialog::launchDialog (newVersionString, releaseNotes);\r
\r
- if (auto* mm = ModalComponentManager::getInstance())\r
- mm->attachCallback (dialogWindow.get(), ModalCallbackFunction::create ([this] (int result)\r
- {\r
- if (result == 1)\r
- askUserForLocationToDownload();\r
+ if (auto* mm = ModalComponentManager::getInstance())\r
+ mm->attachCallback (dialogWindow.get(),\r
+ ModalCallbackFunction::create ([this, asset] (int result)\r
+ {\r
+ if (result == 1)\r
+ askUserForLocationToDownload (asset);\r
\r
- dialogWindow.reset();\r
- }));\r
- }\r
+ dialogWindow.reset();\r
+ }));\r
}\r
\r
//==============================================================================\r
class DownloadAndInstallThread : private ThreadWithProgressWindow\r
{\r
public:\r
- DownloadAndInstallThread (const URL& u, const File& t, std::function<void()>&& cb)\r
+ DownloadAndInstallThread (const VersionInfo::Asset& a, const File& t, std::function<void()>&& cb)\r
: ThreadWithProgressWindow ("Downloading New Version", true, true),\r
- downloadURL (u), targetFolder (t), completionCallback (std::move (cb))\r
+ asset (a), targetFolder (t), completionCallback (std::move (cb))\r
{\r
launchThread (3);\r
}\r
result = install (zipData);\r
\r
if (result.failed())\r
- MessageManager::callAsync ([result] () { AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon, "Installation Failed", result.getErrorMessage()); });\r
+ MessageManager::callAsync ([result] { AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon,\r
+ "Installation Failed",\r
+ result.getErrorMessage()); });\r
else\r
MessageManager::callAsync (completionCallback);\r
}\r
setStatusMessage ("Downloading...");\r
\r
int statusCode = 0;\r
- StringPairArray responseHeaders;\r
-\r
- std::unique_ptr<InputStream> inStream (downloadURL.createInputStream (false, nullptr, nullptr, {}, 0,\r
- &responseHeaders, &statusCode, 0));\r
+ auto inStream = VersionInfo::createInputStreamForAsset (asset, statusCode);\r
\r
if (inStream != nullptr && statusCode == 200)\r
{\r
return Result::ok();\r
}\r
\r
- return Result::fail ("Failed to download from: " + downloadURL.toString (false));\r
+ return Result::fail ("Failed to download from: " + asset.url);\r
}\r
\r
- Result install (MemoryBlock& data)\r
+ Result install (const MemoryBlock& data)\r
{\r
setStatusMessage ("Installing...");\r
\r
- auto result = unzipDownload (data);\r
-\r
- if (threadShouldExit())\r
- result = Result::fail ("Cancelled");\r
-\r
- if (result.failed())\r
- return result;\r
-\r
- return Result::ok();\r
- }\r
-\r
- Result unzipDownload (const MemoryBlock& data)\r
- {\r
MemoryInputStream input (data, false);\r
ZipFile zip (input);\r
\r
if (zip.getNumEntries() == 0)\r
return Result::fail ("The downloaded file was not a valid JUCE file!");\r
\r
- auto unzipTarget = File::createTempFile ({});\r
+ struct ScopedDownloadFolder\r
+ {\r
+ ScopedDownloadFolder (const File& installTargetFolder)\r
+ {\r
+ folder = installTargetFolder.getSiblingFile (installTargetFolder.getFileNameWithoutExtension() + "_download").getNonexistentSibling();\r
+ jassert (folder.createDirectory());\r
+ }\r
+\r
+ ~ScopedDownloadFolder() { folder.deleteRecursively(); }\r
+\r
+ File folder;\r
+ };\r
+\r
+ ScopedDownloadFolder unzipTarget (targetFolder);\r
\r
- if (! unzipTarget.createDirectory())\r
+ if (! unzipTarget.folder.isDirectory())\r
return Result::fail ("Couldn't create a temporary folder to unzip the new version!");\r
\r
- auto r = zip.uncompressTo (unzipTarget);\r
+ auto r = zip.uncompressTo (unzipTarget.folder);\r
\r
if (r.failed())\r
- {\r
- unzipTarget.deleteRecursively();\r
return r;\r
- }\r
\r
- r = applyAutoUpdaterFile (unzipTarget);\r
+ if (threadShouldExit())\r
+ return Result::fail ("Cancelled");\r
+\r
+ #if JUCE_LINUX || JUCE_MAC\r
+ r = setFilePermissions (unzipTarget.folder, zip);\r
\r
if (r.failed())\r
- {\r
- unzipTarget.deleteRecursively();\r
return r;\r
- }\r
+\r
+ if (threadShouldExit())\r
+ return Result::fail ("Cancelled");\r
+ #endif\r
\r
if (targetFolder.exists())\r
{\r
auto oldFolder = targetFolder.getSiblingFile (targetFolder.getFileNameWithoutExtension() + "_old").getNonexistentSibling();\r
\r
if (! targetFolder.moveFileTo (oldFolder))\r
- {\r
- unzipTarget.deleteRecursively();\r
return Result::fail ("Could not remove the existing folder!\n\n"\r
"This may happen if you are trying to download into a directory that requires administrator privileges to modify.\n"\r
"Please select a folder that is writable by the current user.");\r
- }\r
}\r
\r
- if (! unzipTarget.moveFileTo (targetFolder))\r
- {\r
- unzipTarget.deleteRecursively();\r
+ if (! unzipTarget.folder.getChildFile ("JUCE").moveFileTo (targetFolder))\r
return Result::fail ("Could not overwrite the existing folder!\n\n"\r
"This may happen if you are trying to download into a directory that requires administrator privileges to modify.\n"\r
"Please select a folder that is writable by the current user.");\r
- }\r
\r
return Result::ok();\r
}\r
\r
- Result applyAutoUpdaterFile (const File& root)\r
+ Result setFilePermissions (const File& root, const ZipFile& zip)\r
{\r
- auto autoUpdaterFile = root.getChildFile (".autoupdater.xml");\r
+ constexpr uint32 executableFlag = (1 << 22);\r
\r
- if (autoUpdaterFile.existsAsFile())\r
+ for (int i = 0; i < zip.getNumEntries(); ++i)\r
{\r
- #if JUCE_LINUX || JUCE_MAC\r
- if (auto parent = parseXML (autoUpdaterFile))\r
+ auto* entry = zip.getEntry (i);\r
+\r
+ if ((entry->externalFileAttributes & executableFlag) != 0 && entry->filename.getLastCharacter() != '/')\r
{\r
- if (auto* execElement = parent->getChildByName ("EXECUTABLE"))\r
- {\r
- forEachXmlChildElementWithTagName (*execElement, e, "FILE")\r
- {\r
- auto file = root.getChildFile (e->getAllSubText());\r
-\r
- if (file.exists() && ! file.setExecutePermission (true))\r
- return Result::fail ("Failed to set executable file permission for " + file.getFileName());\r
- }\r
- }\r
- }\r
- #endif\r
+ auto exeFile = root.getChildFile (entry->filename);\r
\r
- autoUpdaterFile.deleteFile();\r
+ if (! exeFile.exists())\r
+ return Result::fail ("Failed to find executable file when setting permissions " + exeFile.getFileName());\r
+\r
+ if (! exeFile.setExecutePermission (true))\r
+ return Result::fail ("Failed to set executable file permission for " + exeFile.getFileName());\r
+ }\r
}\r
\r
return Result::ok();\r
}\r
\r
- URL downloadURL;\r
+ VersionInfo::Asset asset;\r
File targetFolder;\r
std::function<void()> completionCallback;\r
};\r
}\r
}\r
\r
-void LatestVersionCheckerAndUpdater::downloadAndInstall (const File& targetFolder)\r
+void LatestVersionCheckerAndUpdater::downloadAndInstall (const VersionInfo::Asset& asset, const File& targetFolder)\r
{\r
- installer.reset (new DownloadAndInstallThread ({ relativeDownloadPath }, targetFolder,\r
+ installer.reset (new DownloadAndInstallThread (asset, targetFolder,\r
[this, targetFolder]\r
{\r
installer.reset();\r
\r
#pragma once\r
\r
+#include "../Utility/Helpers/jucer_VersionInfo.h"\r
+\r
class DownloadAndInstallThread;\r
\r
class LatestVersionCheckerAndUpdater : public DeletedAtShutdown,\r
private:\r
//==============================================================================\r
void run() override;\r
- void queryUpdateServer();\r
- void processResult();\r
- void askUserAboutNewVersion (const String&, const String&);\r
- void askUserForLocationToDownload();\r
- void downloadAndInstall (const File&);\r
+ void askUserAboutNewVersion (const String&, const String&, const VersionInfo::Asset&);\r
+ void askUserForLocationToDownload (const VersionInfo::Asset&);\r
+ void downloadAndInstall (const VersionInfo::Asset&, const File&);\r
\r
//==============================================================================\r
bool showAlertWindows = false;\r
- int statusCode = 0;\r
- String relativeDownloadPath;\r
- var jsonReply;\r
\r
std::unique_ptr<DownloadAndInstallThread> installer;\r
std::unique_ptr<Component> dialogWindow;\r
\r
#pragma once\r
\r
-#include "../JuceLibraryCode/JuceHeader.h"\r
+#include <JuceHeader.h>\r
#include "jucer_CommonHeaders.h"\r
\r
#if JUCE_DEBUG\r
setResizable (true, false);\r
centreWithSize (800, 600);\r
\r
- ApplicationCommandManager& commandManager = ProjucerApplication::getCommandManager();\r
+ auto& commandManager = ProjucerApplication::getCommandManager();\r
\r
- // Register all the app commands..\r
- commandManager.registerAllCommandsForTarget (this);\r
- commandManager.registerAllCommandsForTarget (getProjectContentComponent());\r
+ auto registerAllAppCommands = [&]\r
+ {\r
+ commandManager.registerAllCommandsForTarget (this);\r
+ commandManager.registerAllCommandsForTarget (getProjectContentComponent());\r
+ };\r
\r
- // update key mappings..\r
+ auto updateAppKeyMappings = [&]\r
{\r
commandManager.getKeyMappings()->resetToDefaultMappings();\r
\r
commandManager.getKeyMappings()->restoreFromXml (*keys);\r
\r
addKeyListener (commandManager.getKeyMappings());\r
- }\r
+ };\r
\r
- // don't want the window to take focus when the title-bar is clicked..\r
- setWantsKeyboardFocus (false);\r
+ registerAllAppCommands();\r
+ updateAppKeyMappings();\r
\r
+ setWantsKeyboardFocus (false);\r
getLookAndFeel().setColour (ColourSelector::backgroundColourId, Colours::transparentBlack);\r
-\r
projectNameValue.addListener (this);\r
\r
setResizeLimits (600, 500, 32000, 32000);\r
#endif\r
\r
removeKeyListener (ProjucerApplication::getCommandManager().getKeyMappings());\r
-\r
- // save the current size and position to our settings file..\r
getGlobalProperties().setValue ("lastMainWindowPos", getWindowStateAsString());\r
\r
clearContentComponent();\r
{\r
clearContentComponent();\r
setContentOwned (new ProjectContentComponent(), false);\r
- jassert (getProjectContentComponent() != nullptr);\r
}\r
}\r
\r
\r
void MainWindow::makeVisible()\r
{\r
- restoreWindowPosition();\r
setVisible (true);\r
- addToDesktop(); // (must add before restoring size so that fullscreen will work)\r
+ addToDesktop();\r
restoreWindowPosition();\r
setTitleBarIcon();\r
-\r
getContentComponent()->grabKeyboardFocus();\r
}\r
\r
ProjucerApplication::getApp().mainWindowList.closeWindow (this);\r
}\r
\r
-bool MainWindow::closeProject (Project* project, bool askUserToSave)\r
+bool MainWindow::closeCurrentProject (bool askUserToSave)\r
{\r
- jassert (project == currentProject.get() && project != nullptr);\r
-\r
- if (project == nullptr)\r
+ if (currentProject == nullptr)\r
return true;\r
\r
- project->getStoredProperties().setValue (getProjectWindowPosName(), getWindowStateAsString());\r
+ currentProject->getStoredProperties().setValue (getProjectWindowPosName(), getWindowStateAsString());\r
\r
if (auto* pcc = getProjectContentComponent())\r
{\r
pcc->hideEditor();\r
}\r
\r
- if (! ProjucerApplication::getApp().openDocumentManager.closeAllDocumentsUsingProject (*project, askUserToSave))\r
- return false;\r
-\r
- if (! askUserToSave || (project->saveIfNeededAndUserAgrees() == FileBasedDocument::savedOk))\r
+ if (ProjucerApplication::getApp().openDocumentManager\r
+ .closeAllDocumentsUsingProject (*currentProject, askUserToSave))\r
{\r
- setProject (nullptr);\r
- return true;\r
+ if (! askUserToSave || (currentProject->saveIfNeededAndUserAgrees() == FileBasedDocument::savedOk))\r
+ {\r
+ setProject (nullptr);\r
+ return true;\r
+ }\r
}\r
\r
return false;\r
}\r
\r
-bool MainWindow::closeCurrentProject()\r
-{\r
- return currentProject == nullptr || closeProject (currentProject.get());\r
-}\r
-\r
void MainWindow::moveProject (File newProjectFileToOpen)\r
{\r
auto openInIDE = currentProject->shouldOpenInIDEAfterSaving();\r
\r
- closeProject (currentProject.get(), false);\r
+ closeCurrentProject (false);\r
openFile (newProjectFileToOpen);\r
\r
if (currentProject != nullptr)\r
}\r
}\r
\r
-void MainWindow::setProject (Project* newProject)\r
+void MainWindow::setProject (std::unique_ptr<Project> newProject)\r
{\r
- createProjectContentCompIfNeeded();\r
- getProjectContentComponent()->setProject (newProject);\r
- currentProject.reset (newProject);\r
-\r
- if (currentProject != nullptr)\r
- projectNameValue.referTo (currentProject->getProjectValue (Ids::name));\r
- else\r
+ if (newProject == nullptr)\r
+ {\r
+ getProjectContentComponent()->setProject (nullptr);\r
projectNameValue.referTo (Value());\r
\r
- if (newProject != nullptr)\r
+ currentProject.reset();\r
+ }\r
+ else\r
{\r
+ currentProject = std::move (newProject);\r
+\r
+ createProjectContentCompIfNeeded();\r
+ getProjectContentComponent()->setProject (currentProject.get());\r
+ projectNameValue.referTo (currentProject->getProjectValue (Ids::name));\r
+\r
if (auto* peer = getPeer())\r
- peer->setRepresentedFile (newProject->getFile());\r
+ peer->setRepresentedFile (currentProject->getFile());\r
}\r
\r
ProjucerApplication::getCommandManager().commandStatusChanged();\r
\r
if (file.hasFileExtension (Project::projectFileExtension))\r
{\r
- std::unique_ptr<Project> newDoc (new Project (file));\r
-\r
+ auto newDoc = std::make_unique<Project> (file);\r
auto result = newDoc->loadFrom (file, true);\r
\r
- if (result.wasOk() && closeCurrentProject())\r
+ if (result.wasOk() && closeCurrentProject (true))\r
{\r
- setProject (newDoc.get());\r
- newDoc.release()->setChangedFlag (false);\r
+ setProject (std::move (newDoc));\r
+ currentProject->setChangedFlag (false);\r
\r
- jassert (getProjectContentComponent() != nullptr);\r
getProjectContentComponent()->reloadLastOpenDocuments();\r
-\r
- if (auto* p = getProject())\r
- p->updateDeprecatedProjectSettingsInteractively();\r
+ currentProject->updateDeprecatedProjectSettingsInteractively();\r
\r
return true;\r
}\r
\r
while (windows.size() > 0)\r
{\r
- if (! windows[0]->closeCurrentProject())\r
+ if (! windows[0]->closeCurrentProject (true))\r
return false;\r
\r
windows.remove (0);\r
\r
void MainWindowList::createWindowIfNoneAreOpen()\r
{\r
- if (windows.size() == 0)\r
+ if (windows.isEmpty())\r
createNewMainWindow()->showStartPage();\r
}\r
\r
else\r
#endif\r
{\r
- if (w->closeCurrentProject())\r
+ if (w->closeCurrentProject (true))\r
{\r
windows.removeObject (w);\r
saveCurrentlyOpenProjectList();\r
WeakReference<Component> previousFrontWindow (getFrontmostWindow());\r
\r
auto* w = getOrCreateEmptyWindow();\r
- bool ok = w->openFile (file);\r
+ jassert (w != nullptr);\r
\r
- if (ok)\r
+ if (w->openFile (file))\r
{\r
w->makeVisible();\r
- avoidSuperimposedWindows (w);\r
- }\r
- else\r
- {\r
- closeWindow (w);\r
- }\r
+ checkWindowBounds (*w);\r
\r
- if (openInBackground && previousFrontWindow != nullptr)\r
- previousFrontWindow->toFront (true);\r
+ if (openInBackground && previousFrontWindow != nullptr)\r
+ previousFrontWindow->toFront (true);\r
+\r
+ return true;\r
+ }\r
\r
- return ok;\r
+ closeWindow (w);\r
+ return false;\r
}\r
\r
if (getFrontmostWindow()->tryToOpenPIP (file))\r
\r
MainWindow* MainWindowList::createNewMainWindow()\r
{\r
- auto w = new MainWindow();\r
- windows.add (w);\r
- w->restoreWindowPosition();\r
- avoidSuperimposedWindows (w);\r
- return w;\r
+ windows.add (new MainWindow());\r
+ return windows.getLast();\r
}\r
\r
MainWindow* MainWindowList::getFrontmostWindow (bool createIfNotFound)\r
if (createIfNotFound)\r
{\r
auto* w = createNewMainWindow();\r
- avoidSuperimposedWindows (w);\r
+ jassert (w != nullptr);\r
+\r
w->makeVisible();\r
+ checkWindowBounds (*w);\r
+\r
return w;\r
}\r
\r
return nullptr;\r
}\r
\r
-void MainWindowList::avoidSuperimposedWindows (MainWindow* const mw)\r
+void MainWindowList::checkWindowBounds (MainWindow& windowToCheck)\r
{\r
- for (int i = windows.size(); --i >= 0;)\r
+ auto avoidSuperimposedWindows = [&]\r
{\r
- auto* other = windows.getUnchecked(i);\r
+ for (auto* otherWindow : windows)\r
+ {\r
+ if (otherWindow == nullptr || otherWindow == &windowToCheck)\r
+ continue;\r
\r
- auto b1 = mw->getBounds();\r
- auto b2 = other->getBounds();\r
+ auto boundsToCheck = windowToCheck.getScreenBounds();\r
+ auto otherBounds = otherWindow->getScreenBounds();\r
\r
- if (mw != other\r
- && std::abs (b1.getX() - b2.getX()) < 3\r
- && std::abs (b1.getY() - b2.getY()) < 3\r
- && std::abs (b1.getRight() - b2.getRight()) < 3\r
- && std::abs (b1.getBottom() - b2.getBottom()) < 3)\r
- {\r
- int dx = 40, dy = 30;\r
+ if (std::abs (boundsToCheck.getX() - otherBounds.getX()) < 3\r
+ && std::abs (boundsToCheck.getY() - otherBounds.getY()) < 3\r
+ && std::abs (boundsToCheck.getRight() - otherBounds.getRight()) < 3\r
+ && std::abs (boundsToCheck.getBottom() - otherBounds.getBottom()) < 3)\r
+ {\r
+ int dx = 40, dy = 30;\r
\r
- if (b1.getCentreX() >= mw->getScreenBounds().getCentreX()) dx = -dx;\r
- if (b1.getCentreY() >= mw->getScreenBounds().getCentreY()) dy = -dy;\r
+ if (otherBounds.getCentreX() >= boundsToCheck.getCentreX()) dx = -dx;\r
+ if (otherBounds.getCentreY() >= boundsToCheck.getCentreY()) dy = -dy;\r
\r
- mw->setBounds (b1.translated (dx, dy));\r
+ windowToCheck.setBounds (boundsToCheck.translated (dx, dy));\r
+ }\r
}\r
- }\r
+ };\r
+\r
+ auto ensureWindowIsFullyOnscreen = [&]\r
+ {\r
+ auto windowBounds = windowToCheck.getScreenBounds();\r
+ auto screenLimits = Desktop::getInstance().getDisplays().findDisplayForRect (windowBounds).userArea;\r
+\r
+ if (auto* peer = windowToCheck.getPeer())\r
+ peer->getFrameSize().subtractFrom (screenLimits);\r
+\r
+ auto constrainedX = jlimit (screenLimits.getX(), jmax (screenLimits.getX(), screenLimits.getRight() - windowBounds.getWidth()), windowBounds.getX());\r
+ auto constrainedY = jlimit (screenLimits.getY(), jmax (screenLimits.getY(), screenLimits.getBottom() - windowBounds.getHeight()), windowBounds.getY());\r
+\r
+ Point<int> constrainedTopLeft (constrainedX, constrainedY);\r
+\r
+ if (windowBounds.getPosition() != constrainedTopLeft)\r
+ windowToCheck.setTopLeftPosition (constrainedTopLeft);\r
+ };\r
+\r
+ avoidSuperimposedWindows();\r
+ ensureWindowIsFullyOnscreen();\r
}\r
\r
void MainWindowList::saveCurrentlyOpenProjectList()\r
//==============================================================================\r
bool canOpenFile (const File& file) const;\r
bool openFile (const File& file);\r
- void setProject (Project* newProject);\r
- Project* getProject() const { return currentProject.get(); }\r
+\r
+ void setProject (std::unique_ptr<Project> newProject);\r
+ Project* getProject() const { return currentProject.get(); }\r
+\r
bool tryToOpenPIP (const File& f);\r
\r
void makeVisible();\r
void restoreWindowPosition();\r
- bool closeProject (Project* project, bool askToSave = true);\r
- bool closeCurrentProject();\r
+ bool closeCurrentProject (bool askToSave);\r
void moveProject (File newProjectFile);\r
\r
void showStartPage();\r
void reopenLastProjects();\r
void saveCurrentlyOpenProjectList();\r
\r
- void avoidSuperimposedWindows (MainWindow*);\r
+ void checkWindowBounds (MainWindow&);\r
\r
void sendLookAndFeelChange();\r
\r
#pragma once\r
\r
//[Headers] -- You can add your own extra header files here --\r
-%%include_juce_header%%\r
+%%include_juce%%\r
//[/Headers]\r
\r
%%include_files_h%%\r
public:\r
//==============================================================================\r
%%class_name%% (%%constructor_params%%);\r
- ~%%class_name%%();\r
+ ~%%class_name%%() override;\r
\r
//==============================================================================\r
//[UserMethods] -- You can add your own custom methods in this section.\r
==============================================================================\r
*/\r
\r
-#include "../JuceLibraryCode/JuceHeader.h"\r
+%%include_juce%%\r
#include "%%filename%%"\r
\r
%%component_begin%%\r
else\r
r << " g.setColour (Colours::black.withAlpha (" << CodeHelpers::floatLiteral (opacity, 3) << "));\n";\r
\r
- r << " jassert (" << imageVariable << " != 0);\n"\r
- << " if (" << imageVariable << " != 0)\n"\r
+ r << " jassert (" << imageVariable << " != nullptr);\n"\r
+ << " if (" << imageVariable << " != nullptr)\n"\r
<< " " << imageVariable << "->drawWithin (g, Rectangle<int> (x, y, width, height).toFloat(),\n"\r
<< " " << String::repeatedString (" ", imageVariable.length() + 18)\r
<< (mode == stretched ? "RectanglePlacement::stretchToFit"\r
}
//==============================================================================
-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));
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));
~GeneratedCode();\r
\r
//==============================================================================\r
- void applyToCode (String& code,\r
- const File& targetFile,\r
- const String& oldFileWithUserData,\r
- Project* project) const;\r
-\r
+ void applyToCode (String& code, const File& targetFile, const String& oldFileWithUserData) const;\r
int getUniqueSuffix();\r
\r
//==============================================================================\r
String className;\r
String componentName;\r
String parentClassInitialiser; // optional parent class initialiser to go before the items in the initialisers list\r
- StringArray initialisers; // (a list of the member variables that need initalising after the constructor declaration)\r
+ StringArray initialisers; // (a list of the member variables that need initialising after the constructor declaration)\r
String parentClasses;\r
String constructorParams;\r
String privateMemberDeclarations;\r
String existingHeader (header->getCodeDocument().getAllContent());\r
String existingCpp (cpp->getCodeDocument().getAllContent());\r
\r
- generated.applyToCode (headerTemplate, headerFile,\r
- existingHeader, project);\r
-\r
- generated.applyToCode (cppTemplate, headerFile.withFileExtension (".cpp"),\r
- existingCpp, project);\r
+ generated.applyToCode (headerTemplate, headerFile, existingHeader);\r
+ generated.applyToCode (cppTemplate, headerFile.withFileExtension (".cpp"), existingCpp);\r
\r
if (isInitial)\r
{\r
if (exporter->canLaunchProject())\r
defs.add (exporter->getExporterIdentifierMacro() + "=1");\r
\r
- // Use the JUCE implementation of std::function until the live build\r
- // engine can compile the one from the standard library\r
- defs.add (" _LIBCPP_FUNCTIONAL=1");\r
defs.removeEmptyStrings();\r
\r
return defs.joinIntoString (" ");\r
auto isVSTHost = project.getEnabledModules().isModuleEnabled ("juce_audio_processors")\r
&& (project.isConfigFlagEnabled ("JUCE_PLUGINHOST_VST3") || project.isConfigFlagEnabled ("JUCE_PLUGINHOST_VST"));\r
\r
- auto isPluginProject = proj.getProjectType().isAudioPlugin();\r
+ auto isPluginProject = proj.isAudioPluginProject();\r
\r
OwnedArray<LibraryModule> modules;\r
proj.getEnabledModules().createRequiredModules (modules);\r
StringArray getSystemIncludePaths()\r
{\r
StringArray paths;\r
+ paths.add (project.getGeneratedCodeFolder().getFullPathName());\r
paths.addArray (getSearchPathsFromString (project.getCompileEngineSettings().getSystemHeaderPathString()));\r
\r
auto isVSTHost = project.getEnabledModules().isModuleEnabled ("juce_audio_processors")\r
\r
auto customVst3Path = getAppSettings().getStoredPath (Ids::vst3Path, TargetOS::getThisOS()).get().toString();\r
\r
- if (customVst3Path.isNotEmpty() && (project.getProjectType().isAudioPlugin() || isVSTHost))\r
+ if (customVst3Path.isNotEmpty() && (project.isAudioPluginProject() || isVSTHost))\r
paths.add (customVst3Path);\r
\r
OwnedArray<LibraryModule> modules;\r
{\r
paths.addIfNotAlreadyThere (module->getFolder().getParentDirectory().getFullPathName());\r
\r
- if (customVst3Path.isEmpty() && (project.getProjectType().isAudioPlugin() || isVSTHost))\r
+ if (customVst3Path.isEmpty() && (project.isAudioPluginProject() || isVSTHost))\r
if (module->getID() == "juce_audio_processors")\r
paths.addIfNotAlreadyThere (module->getFolder().getChildFile ("format_types").getChildFile ("VST3_SDK").getFullPathName());\r
}\r
#include "../Application/jucer_Headers.h"\r
#include "jucer_DownloadCompileEngineThread.h"\r
#include "../LiveBuildEngine/jucer_CompileEngineDLL.h"\r
+#include "../Utility/Helpers/jucer_VersionInfo.h"\r
\r
//==============================================================================\r
bool DownloadCompileEngineThread::downloadAndInstall()\r
\r
Result DownloadCompileEngineThread::download (MemoryBlock& dest)\r
{\r
- int statusCode = 302;\r
- const int timeoutMs = 10000;\r
- StringPairArray responseHeaders;\r
+ auto info = VersionInfo::fetchFromUpdateServer (ProjectInfo::versionString);\r
\r
- URL url = getDownloadUrl();\r
- std::unique_ptr<InputStream> in (url.createInputStream (false, nullptr, nullptr,\r
- String(), timeoutMs, &responseHeaders,\r
- &statusCode, 0));\r
+ if (info == nullptr)\r
+ return Result::fail ("Download error: cannot communicate with server");\r
\r
- if (in == nullptr || statusCode != 200)\r
- return Result::fail ("Download error: cannot establish connection");\r
+ auto requiredAssetName = []\r
+ {\r
+ String name ("JUCECompileEngine_");\r
\r
- MemoryOutputStream mo (dest, true);\r
+ #if JUCE_MAC\r
+ name << "osx_";\r
+ #elif JUCE_WINDOWS\r
+ name << "windows_";\r
+ #else\r
+ jassertfalse;\r
+ #endif\r
\r
- int64 size = in->getTotalLength();\r
- int64 bytesReceived = -1;\r
- String msg("Downloading... (123)");\r
+ return name + ProjectInfo::versionString + ".zip";\r
+ }();\r
\r
- for (int64 pos = 0; pos < size; pos += bytesReceived)\r
+ for (auto& asset : info->assets)\r
{\r
- setStatusMessage (msg.replace ("123", File::descriptionOfSizeInBytes (pos)));\r
+ if (asset.name == requiredAssetName)\r
+ {\r
+ int statusCode = 0;\r
+ auto in = VersionInfo::createInputStreamForAsset (asset, statusCode);\r
+\r
+ if (in == nullptr || statusCode != 200)\r
+ return Result::fail ("Download error: cannot establish connection");\r
+\r
+ MemoryOutputStream mo (dest, true);\r
+\r
+ int64 size = in->getTotalLength();\r
+ int64 bytesReceived = -1;\r
+ String msg("Downloading... (123)");\r
+\r
+ for (int64 pos = 0; pos < size; pos += bytesReceived)\r
+ {\r
+ setStatusMessage (msg.replace ("123", File::descriptionOfSizeInBytes (pos)));\r
+\r
+ if (threadShouldExit())\r
+ return Result::fail ("Download error: operation interrupted");\r
\r
- if (threadShouldExit())\r
- return Result::fail ("Download error: operation interrupted");\r
+ bytesReceived = mo.writeFromInputStream (*in, 8192);\r
\r
- bytesReceived = mo.writeFromInputStream (*in, 8192);\r
+ if (bytesReceived == 0)\r
+ return Result::fail ("Download error: lost connection");\r
+ }\r
\r
- if (bytesReceived == 0)\r
- return Result::fail ("Download error: lost connection");\r
+ return Result::ok();\r
+ }\r
}\r
\r
- return Result::ok();\r
+ return Result::fail ("Download error: no downloads available");\r
}\r
\r
Result DownloadCompileEngineThread::install (const MemoryBlock& data, File& targetFolder)\r
return zip.uncompressTo (targetFolder);\r
}\r
\r
-URL DownloadCompileEngineThread::getDownloadUrl()\r
-{\r
- String urlStub ("http://assets.roli.com/juce/JUCECompileEngine_");\r
-\r
- #if JUCE_MAC\r
- urlStub << "osx_";\r
- #elif JUCE_WINDOWS\r
- urlStub << "windows_";\r
- #else\r
- jassertfalse;\r
- #endif\r
-\r
- return urlStub + ProjectInfo::versionString + ".zip";\r
-}\r
-\r
File DownloadCompileEngineThread::getInstallFolder()\r
{\r
return CompileEngineDLL::getVersionedUserAppSupportFolder();\r
props.add (new CppStandardWarningComponent());\r
\r
group.properties.clear();\r
+ exporterModulePathDefaultValues.clear();\r
exporterModulePathValues.clear();\r
\r
for (Project::ExporterIterator exporter (project); exporter.next();)\r
if (exporter->isCLion())\r
continue;\r
\r
- exporterModulePathValues.add (exporter->getPathForModuleValue (moduleID));\r
+ exporterModulePathDefaultValues.add (exporter->getPathForModuleValue (moduleID));\r
+ auto& defaultValue = exporterModulePathDefaultValues.getReference (exporterModulePathDefaultValues.size() - 1);\r
\r
- auto& value = exporterModulePathValues.getReference (exporterModulePathValues.size() - 1);\r
- value.onDefaultChange = [this] { startTimer (50); };\r
+ exporterModulePathValues.add (defaultValue.getPropertyAsValue());\r
\r
- auto* pathComponent = new FilePathPropertyComponent (value, "Path for " + exporter->getName().quoted(), true,\r
- exporter->getTargetOSForExporter() == TargetOS::getThisOS(),\r
- "*", project.getProjectFolder());\r
+ auto pathComponent = std::make_unique<FilePathPropertyComponent> (defaultValue,\r
+ "Path for " + exporter->getName().quoted(),\r
+ true,\r
+ exporter->getTargetOSForExporter() == TargetOS::getThisOS(),\r
+ "*",\r
+ project.getProjectFolder());\r
\r
- props.add (pathComponent,\r
+ pathComponent->setEnabled (! modules.shouldUseGlobalPath (moduleID));\r
+\r
+ props.add (pathComponent.release(),\r
"A path to the folder that contains the " + moduleID + " module when compiling the "\r
+ exporter->getName().quoted() + " target. "\r
"This can be an absolute path, or relative to the jucer project folder, but it "\r
"must be valid on the filesystem of the target machine that will be performing this build. If this "\r
"is empty then the global path will be used.");\r
+ }\r
\r
- pathComponent->setEnabled (! modules.shouldUseGlobalPath (moduleID));\r
+ for (int i = 0; i < exporterModulePathDefaultValues.size(); ++i)\r
+ {\r
+ exporterModulePathDefaultValues.getReference (i).onDefaultChange = [this] { startTimer (50); };\r
+ exporterModulePathValues.getReference (i).addListener (this);\r
}\r
\r
globalPathValue.removeListener (this);\r
String getModuleID() const noexcept { return moduleID; }\r
\r
private:\r
- void valueChanged (Value&) override { startTimer (50); }\r
- void timerCallback() override { stopTimer(); refresh(); }\r
+ void valueChanged (Value& v) override\r
+ {\r
+ auto isExporterPathValue = [&]\r
+ {\r
+ for (auto& exporterValue : exporterModulePathValues)\r
+ if (exporterValue.refersToSameSourceAs (v))\r
+ return true;\r
+\r
+ return false;\r
+ }();\r
+\r
+ if (isExporterPathValue)\r
+ project.rescanExporterPathModules();\r
+\r
+ startTimer (50);\r
+ }\r
+\r
+ void timerCallback() override\r
+ {\r
+ stopTimer();\r
+ refresh();\r
+ }\r
\r
//==============================================================================\r
- Array<ValueWithDefault> exporterModulePathValues;\r
+ Array<ValueWithDefault> exporterModulePathDefaultValues;\r
+ Array<Value> exporterModulePathValues;\r
Value globalPathValue;\r
\r
OwnedArray <Project::ConfigFlag> configFlags;\r
void ProjectContentComponent::closeProject()\r
{\r
if (auto* mw = findParentComponentOfClass<MainWindow>())\r
- mw->closeCurrentProject();\r
+ mw->closeCurrentProject (true);\r
}\r
\r
void ProjectContentComponent::showProjectSettings()\r
auto& xcodeExporter = dynamic_cast<XcodeProjectExporter&> (exporter);\r
\r
if (project.isAUPluginHost())\r
- xcodeExporter.xcodeFrameworks.addTokens (xcodeExporter.isOSX() ? "AudioUnit CoreAudioKit" : "CoreAudioKit", false);\r
+ {\r
+ xcodeExporter.xcodeFrameworks.add ("CoreAudioKit");\r
+\r
+ if (xcodeExporter.isOSX())\r
+ xcodeExporter.xcodeFrameworks.add ("AudioUnit");\r
+ }\r
\r
auto frameworks = moduleInfo.moduleInfo [xcodeExporter.isOSX() ? "OSXFrameworks" : "iOSFrameworks"].toString();\r
xcodeExporter.xcodeFrameworks.addTokens (frameworks, ", ", {});\r
\r
bool EnabledModuleList::isAudioPluginModuleMissing() const\r
{\r
- return project.getProjectType().isAudioPlugin()\r
+ return project.isAudioPluginProject()\r
&& ! isModuleEnabled ("juce_audio_plugin_client");\r
}\r
\r
oldExporters.set ("MSVC6", "MSVC6");\r
oldExporters.set ("VS2010", "Visual Studio 2010");\r
oldExporters.set ("VS2012", "Visual Studio 2012");\r
+ oldExporters.set ("VS2013", "Visual Studio 2013");\r
\r
for (auto& key : oldExporters.getAllKeys())\r
{\r
+ getVersionElement (v, 0);\r
}\r
\r
-static int getBuiltJuceVersion()\r
+static constexpr int getBuiltJuceVersion()\r
{\r
return JUCE_MAJOR_VERSION * 100000\r
+ JUCE_MINOR_VERSION * 1000\r
\r
static bool isModuleNewerThanProjucer (const ModuleDescription& module)\r
{\r
- if (module.getID().startsWith ("juce_")\r
- && getJuceVersion (module.getVersion()) > getBuiltJuceVersion())\r
- return true;\r
-\r
- return false;\r
+ return module.getID().startsWith ("juce_") && getJuceVersion (module.getVersion()) > getBuiltJuceVersion();\r
}\r
\r
void Project::warnAboutOldProjucerVersion()\r
{\r
if (isModuleNewerThanProjucer ({ juceModule.second }))\r
{\r
- // Projucer is out of date!\r
if (ProjucerApplication::getApp().isRunningCommandLine)\r
std::cout << "WARNING! This version of the Projucer is out-of-date!" << std::endl;\r
else\r
props.add (new TextPropertyComponent (bundleIdentifierValue, "Bundle Identifier", 256, false),\r
"A unique identifier for this product, mainly for use in OSX/iOS builds. It should be something like 'com.yourcompanyname.yourproductname'");\r
\r
- if (getProjectType().isAudioPlugin())\r
+ if (isAudioPluginProject())\r
createAudioPluginPropertyEditors (props);\r
\r
{\r
File getBinaryDataCppFile (int index) const;\r
File getBinaryDataHeaderFile() const { return getBinaryDataCppFile (0).withFileExtension (".h"); }\r
\r
- String getAppConfigFilename() const { return "AppConfig.h"; }\r
- String getJuceSourceFilenameRoot() const { return "JuceLibraryCode"; }\r
- String getJuceSourceHFilename() const { return "JuceHeader.h"; }\r
+ static String getAppConfigFilename() { return "AppConfig.h"; }\r
+ static String getJuceSourceHFilename() { return "JuceHeader.h"; }\r
\r
//==============================================================================\r
template <class FileType>\r
String getVSTNumMIDIInputsString() const { return pluginVSTNumMidiInputsValue.get(); }\r
String getVSTNumMIDIOutputsString() const { return pluginVSTNumMidiOutputsValue.get(); }\r
\r
- //==============================================================================\r
static bool checkMultiChoiceVar (const ValueWithDefault& valueToCheck, Identifier idToCheck) noexcept\r
{\r
if (! valueToCheck.get().isArray())\r
return false;\r
}\r
\r
- //==============================================================================\r
- bool shouldBuildVST() const { return checkMultiChoiceVar (pluginFormatsValue, Ids::buildVST); }\r
- bool shouldBuildVST3() const { return checkMultiChoiceVar (pluginFormatsValue, Ids::buildVST3); }\r
- bool shouldBuildAU() const { return checkMultiChoiceVar (pluginFormatsValue, Ids::buildAU); }\r
- bool shouldBuildAUv3() const { return checkMultiChoiceVar (pluginFormatsValue, Ids::buildAUv3); }\r
- bool shouldBuildRTAS() const { return checkMultiChoiceVar (pluginFormatsValue, Ids::buildRTAS); }\r
- bool shouldBuildAAX() const { return checkMultiChoiceVar (pluginFormatsValue, Ids::buildAAX); }\r
- bool shouldBuildStandalonePlugin() const { return checkMultiChoiceVar (pluginFormatsValue, Ids::buildStandalone); }\r
- bool shouldBuildUnityPlugin() const { return checkMultiChoiceVar (pluginFormatsValue, Ids::buildUnity); }\r
- bool shouldEnableIAA() const { return checkMultiChoiceVar (pluginFormatsValue, Ids::enableIAA); }\r
+ bool isAudioPluginProject() const { return getProjectType().isAudioPlugin(); }\r
+\r
+ bool shouldBuildVST() const { return isAudioPluginProject() && checkMultiChoiceVar (pluginFormatsValue, Ids::buildVST); }\r
+ bool shouldBuildVST3() const { return isAudioPluginProject() && checkMultiChoiceVar (pluginFormatsValue, Ids::buildVST3); }\r
+ bool shouldBuildAU() const { return isAudioPluginProject() && checkMultiChoiceVar (pluginFormatsValue, Ids::buildAU); }\r
+ bool shouldBuildAUv3() const { return isAudioPluginProject() && checkMultiChoiceVar (pluginFormatsValue, Ids::buildAUv3); }\r
+ bool shouldBuildRTAS() const { return isAudioPluginProject() && checkMultiChoiceVar (pluginFormatsValue, Ids::buildRTAS); }\r
+ bool shouldBuildAAX() const { return isAudioPluginProject() && checkMultiChoiceVar (pluginFormatsValue, Ids::buildAAX); }\r
+ bool shouldBuildStandalonePlugin() const { return isAudioPluginProject() && checkMultiChoiceVar (pluginFormatsValue, Ids::buildStandalone); }\r
+ bool shouldBuildUnityPlugin() const { return isAudioPluginProject() && checkMultiChoiceVar (pluginFormatsValue, Ids::buildUnity); }\r
+ bool shouldEnableIAA() const { return isAudioPluginProject() && checkMultiChoiceVar (pluginFormatsValue, Ids::enableIAA); }\r
\r
- //==============================================================================\r
bool isPluginSynth() const { return checkMultiChoiceVar (pluginCharacteristicsValue, Ids::pluginIsSynth); }\r
bool pluginWantsMidiInput() const { return checkMultiChoiceVar (pluginCharacteristicsValue, Ids::pluginWantsMidiIn); }\r
bool pluginProducesMidiOutput() const { return checkMultiChoiceVar (pluginCharacteristicsValue, Ids::pluginProducesMidiOut); }\r
bool isPluginAAXBypassDisabled() const { return checkMultiChoiceVar (pluginCharacteristicsValue, Ids::pluginAAXDisableBypass); }\r
bool isPluginAAXMultiMonoDisabled() const { return checkMultiChoiceVar (pluginCharacteristicsValue, Ids::pluginAAXDisableMultiMono); }\r
\r
- //==============================================================================\r
static StringArray getAllAUMainTypeStrings() noexcept;\r
static Array<var> getAllAUMainTypeVars() noexcept;\r
Array<var> getDefaultAUMainTypes() const noexcept;\r
androidKeyStorePass (settings, Ids::androidKeyStorePass, getUndoManager(), "android"),\r
androidKeyAlias (settings, Ids::androidKeyAlias, getUndoManager(), "androiddebugkey"),\r
androidKeyAliasPass (settings, Ids::androidKeyAliasPass, getUndoManager(), "android"),\r
- gradleVersion (settings, Ids::gradleVersion, getUndoManager(), "4.10"),\r
+ gradleVersion (settings, Ids::gradleVersion, getUndoManager(), "5.4.1"),\r
gradleToolchain (settings, Ids::gradleToolchain, getUndoManager(), "clang"),\r
- androidPluginVersion (settings, Ids::androidPluginVersion, getUndoManager(), "3.2.1"),\r
+ androidPluginVersion (settings, Ids::androidPluginVersion, getUndoManager(), "3.5.3"),\r
AndroidExecutable (getAppSettings().getStoredPath (Ids::androidStudioExePath, TargetOS::getThisOS()).get().toString())\r
{\r
name = getName();\r
for (auto& d : StringArray::fromLines (androidJavaLibs.get().toString()))\r
mo << " implementation files('libs/" << File (d).getFileName() << "')" << newLine;\r
\r
+ if (isInAppBillingEnabled())\r
+ mo << " implementation 'com.android.billingclient:billing:2.1.0'" << newLine;\r
+\r
if (areRemoteNotificationsEnabled())\r
{\r
mo << " implementation 'com.google.firebase:firebase-core:16.0.1'" << newLine;\r
if (areRemoteNotificationsEnabled())\r
addOptJavaFolderToSourceSetsForModule (javaSourceSets, modules, "juce_gui_extra");\r
\r
+ if (project.getEnabledModules().isModuleEnabled ("juce_product_unlocking") && isInAppBillingEnabled())\r
+ addOptJavaFolderToSourceSetsForModule (javaSourceSets, modules, "juce_product_unlocking");\r
+\r
MemoryOutputStream mo;\r
mo.setNewLineString ("\n");\r
\r
bool arePushNotificationsEnabled() const { return androidPushNotifications.get(); }\r
bool areRemoteNotificationsEnabled() const { return arePushNotificationsEnabled() && androidEnableRemoteNotifications.get(); }\r
\r
+ bool isInAppBillingEnabled() const { return androidInAppBillingPermission.get(); }\r
+\r
String getJNIActivityClassName() const\r
{\r
return getActivityClassString().replaceCharacter ('.', '/');\r
}\r
\r
- static LibraryModule* getCoreModule (const OwnedArray<LibraryModule>& modules)\r
- {\r
- for (int i = modules.size(); --i >= 0;)\r
- if (modules.getUnchecked (i)->getID() == "juce_core")\r
- return modules.getUnchecked (i);\r
-\r
- return nullptr;\r
- }\r
-\r
//==============================================================================\r
String getNativeModuleBinaryName (const AndroidBuildConfiguration& config) const\r
{\r
mo << " \"" << file.toUnixStyle() << "\"" << newLine;\r
\r
if ((! projectItem.shouldBeCompiled()) || (! shouldFileBeCompiledByDefault (f))\r
- || (getProject().getProjectType().isAudioPlugin()\r
+ || (getProject().isAudioPluginProject()\r
&& targetType != ProjectType::Target::SharedCodeTarget\r
&& targetType != ProjectType::Target::StandalonePlugIn))\r
{\r
if (arePushNotificationsEnabled())\r
{\r
defines.set ("JUCE_PUSH_NOTIFICATIONS", "1");\r
- defines.set ("JUCE_PUSH_NOTIFICATIONS_ACTIVITY", String::formatted("\"%s\"", getJNIActivityClassName().toUTF8()));\r
+ defines.set ("JUCE_PUSH_NOTIFICATIONS_ACTIVITY", getJNIActivityClassName().quoted());\r
}\r
\r
- if (androidInAppBillingPermission.get())\r
+ if (isInAppBillingEnabled())\r
defines.set ("JUCE_IN_APP_PURCHASES", "1");\r
\r
if (supportsGLv3())\r
StringArray s = StringArray::fromTokens (androidOtherPermissions.get().toString(), ", ", {});\r
\r
if (androidInternetNeeded.get())\r
+ {\r
s.add ("android.permission.INTERNET");\r
+ s.add ("android.permission.CHANGE_WIFI_MULTICAST_STATE");\r
+ }\r
\r
if (androidMicNeeded.get())\r
s.add ("android.permission.RECORD_AUDIO");\r
if (androidExternalWritePermission.get())\r
s.add ("android.permission.WRITE_EXTERNAL_STORAGE");\r
\r
- if (androidInAppBillingPermission.get())\r
+ if (isInAppBillingEnabled())\r
s.add ("com.android.vending.BILLING");\r
\r
if (androidVibratePermission.get())\r
template <class Target, class Exporter>\r
void getFileInfoList (Target& target, Exporter& exporter, const Project::Item& projectItem, std::vector<std::tuple<String, bool, String>>& fileInfoList) const\r
{\r
- auto targetType = (getProject().getProjectType().isAudioPlugin() ? target.type : Target::Type::SharedCodeTarget);\r
+ auto targetType = (getProject().isAudioPluginProject() ? target.type : Target::Type::SharedCodeTarget);\r
\r
if (projectItem.isGroup())\r
{\r
\r
if (config.exporter.isLinux())\r
{\r
- if (target.isDynamicLibrary() || getProject().getProjectType().isAudioPlugin())\r
+ if (target.isDynamicLibrary() || getProject().isAudioPluginProject())\r
flags.add ("-fPIC");\r
\r
auto packages = getPackages();\r
{\r
auto librarySearchPaths = config.getLibrarySearchPaths();\r
\r
- if (getProject().getProjectType().isAudioPlugin() && target.type != ProjectType::Target::SharedCodeTarget)\r
+ if (getProject().isAudioPluginProject() && target.type != ProjectType::Target::SharedCodeTarget)\r
librarySearchPaths.add (RelativePath (getSharedCodePath (config), RelativePath::buildTargetFolder).getParentDirectory().toUnixStyle().quoted());\r
\r
return librarySearchPaths;\r
xml.createNewChildElement ("Option")->setAttribute ("type", getTypeIndex (target.type));\r
xml.createNewChildElement ("Option")->setAttribute ("compiler", "gcc");\r
\r
- if (getProject().getProjectType().isAudioPlugin() && target.type != ProjectType::Target::SharedCodeTarget)\r
+ if (getProject().isAudioPluginProject() && target.type != ProjectType::Target::SharedCodeTarget)\r
xml.createNewChildElement ("Option")->setAttribute ("external_deps", getSharedCodePath (config));\r
\r
{\r
{\r
auto* linker = xml.createNewChildElement ("Linker");\r
\r
- if (getProject().getProjectType().isAudioPlugin() && target.type != ProjectType::Target::SharedCodeTarget)\r
+ if (getProject().isAudioPluginProject() && target.type != ProjectType::Target::SharedCodeTarget)\r
setAddOption (*linker, "option", getSharedCodePath (config).quoted());\r
\r
for (auto& flag : getLinkerFlags (config, target))\r
// the single target\r
CodeBlocksTarget& getMainTarget() const\r
{\r
- if (getProject().getProjectType().isAudioPlugin())\r
+ if (getProject().isAudioPluginProject())\r
return getTargetWithType (ProjectType::Target::SharedCodeTarget);\r
\r
for (auto* target : targets)\r
\r
CodeBlocksTarget& getTargetForProjectItem (const Project::Item& projectItem) const\r
{\r
- if (getProject().getProjectType().isAudioPlugin())\r
+ if (getProject().isAudioPluginProject())\r
{\r
if (! projectItem.shouldBeCompiled())\r
return getTargetWithType (ProjectType::Target::SharedCodeTarget);\r
\r
void createConfigProperties (PropertyListBuilder& props) override\r
{\r
- addVisualStudioPluginInstallPathProperties (props);\r
+ if (project.isAudioPluginProject())\r
+ addVisualStudioPluginInstallPathProperties (props);\r
\r
props.add (new ChoicePropertyComponent (architectureTypeValue, "Architecture",\r
{ get32BitArchName(), get64BitArchName() },\r
//==============================================================================\r
void addFilesToCompile (const Project::Item& projectItem, XmlElement& cpps, XmlElement& headers, XmlElement& otherFiles) const\r
{\r
- auto targetType = (getOwner().getProject().getProjectType().isAudioPlugin() ? type : SharedCodeTarget);\r
+ auto targetType = (getOwner().getProject().isAudioPluginProject() ? type : SharedCodeTarget);\r
\r
if (projectItem.isGroup())\r
{\r
bool addFilesToFilter (const Project::Item& projectItem, const String& path,\r
XmlElement& cpps, XmlElement& headers, XmlElement& otherFiles, XmlElement& groups) const\r
{\r
- auto targetType = (getOwner().getProject().getProjectType().isAudioPlugin() ? type : SharedCodeTarget);\r
+ auto targetType = (getOwner().getProject().isAudioPluginProject() ? type : SharedCodeTarget);\r
\r
if (projectItem.isGroup())\r
{\r
\r
String getPostBuildSteps (const MSVCBuildConfiguration& config) const\r
{\r
- auto postBuild = config.getPostbuildCommandString();\r
+ auto postBuild = config.getPostbuildCommandString().replace ("\n", "\r\n");;\r
auto extraPostBuild = getExtraPostBuildSteps (config);\r
\r
return postBuild + String (postBuild.isNotEmpty() && extraPostBuild.isNotEmpty() ? "\r\n" : "") + extraPostBuild;\r
\r
String getPreBuildSteps (const MSVCBuildConfiguration& config) const\r
{\r
- auto preBuild = config.getPrebuildCommandString();\r
+ auto preBuild = config.getPrebuildCommandString().replace ("\n", "\r\n");;\r
auto extraPreBuild = getExtraPreBuildSteps (config);\r
\r
return preBuild + String (preBuild.isNotEmpty() && extraPreBuild.isNotEmpty() ? "\r\n" : "") + extraPreBuild;\r
}\r
else\r
{\r
- if (! getProject().getProjectType().isAudioPlugin())\r
+ if (! getProject().isAudioPluginProject())\r
out << "all : " << target->getBuildProduct() << newLine << newLine;\r
\r
target->writeTargetLine (out, packages);\r
{\r
Array<std::pair<File, String>> targetFiles;\r
\r
- auto targetType = (p.getProjectType().isAudioPlugin() ? target->type : MakefileTarget::SharedCodeTarget);\r
+ auto targetType = (p.isAudioPluginProject() ? target->type : MakefileTarget::SharedCodeTarget);\r
\r
for (auto& f : files)\r
if (p.getTargetTypeFromFilePath (f.first, true) == targetType)\r
\r
phonyTargetLine << ".PHONY: clean all strip";\r
\r
- if (! getProject().getProjectType().isAudioPlugin())\r
+ if (! getProject().isAudioPluginProject())\r
return phonyTargetLine.toString();\r
\r
for (auto target : targets)\r
static String getSDKDisplayName (int version) { return getVersionName (version) + " SDK"; }\r
static String getSDKRootName (int version) { return "macosx" + getVersionName (version); }\r
\r
+ static String getOSXSDKVersion (const String& sdkVersion)\r
+ {\r
+ for (int v = oldestSDKVersion; v <= currentSDKVersion; ++v)\r
+ if (sdkVersion == getSDKDisplayName (v))\r
+ return getSDKRootName (v);\r
+\r
+ return "macosx";\r
+ }\r
+\r
template<class ContainerType>\r
static ContainerType getSDKChoiceList (int oldestVersion, bool displayName)\r
{\r
customXcodeResourceFoldersValue (settings, Ids::customXcodeResourceFolders, getUndoManager()),\r
customXcassetsFolderValue (settings, Ids::customXcassetsFolder, getUndoManager()),\r
appSandboxValue (settings, Ids::appSandbox, getUndoManager()),\r
+ appSandboxInheritanceValue (settings, Ids::appSandboxInheritance, getUndoManager()),\r
appSandboxOptionsValue (settings, Ids::appSandboxOptions, getUndoManager(), Array<var>(), ","),\r
hardenedRuntimeValue (settings, Ids::hardenedRuntime, getUndoManager()),\r
hardenedRuntimeOptionsValue (settings, Ids::hardenedRuntimeOptions, getUndoManager(), Array<var>(), ","),\r
Array<var> getHardenedRuntimeOptions() const { return *hardenedRuntimeOptionsValue.get().getArray(); }\r
\r
bool isAppSandboxEnabled() const { return appSandboxValue.get(); }\r
+ bool isAppSandboxInhertianceEnabled() const { return appSandboxInheritanceValue.get(); }\r
Array<var> getAppSandboxOptions() const { return *appSandboxOptionsValue.get().getArray(); }\r
\r
bool isMicrophonePermissionEnabled() const { return microphonePermissionNeededValue.get(); }\r
"This way you can specify them for OS X and iOS separately, and modify the content of the resource folders "\r
"without re-saving the Projucer project.");\r
\r
- if (getProject().getProjectType().isAudioPlugin())\r
+ if (getProject().isAudioPluginProject())\r
props.add (new ChoicePropertyComponent (duplicateAppExResourcesFolderValue, "Add Duplicate Resources Folder to App Extension"),\r
"Disable this to prevent the Projucer from creating a duplicate resources folder for AUv3 app extensions.");\r
\r
props.add (new ChoicePropertyComponent (appSandboxValue, "Use App Sandbox"),\r
"Enable this to use the app sandbox.");\r
\r
+ props.add (new ChoicePropertyComponentWithEnablement (appSandboxInheritanceValue, appSandboxValue, "App Sandbox Inheritance"),\r
+ "If app sandbox is enabled, this setting will configure a child process to inherit the sandbox of its parent. "\r
+ "Note that if you enable this and have specified any other app sandbox entitlements below, the child process "\r
+ "will fail to launch.");\r
+\r
std::vector<std::pair<String, String>> sandboxOptions\r
{\r
{ "Network: Incoming Connections (Server)", "network.server" },\r
{ "File Access: Music Folder (Read Only)", "assets.music.read-only" },\r
{ "File Access: Music Folder (Read/Write)", "assets.music.read-write" },\r
{ "File Access: Movies Folder (Read Only)", "assets.movies.read-only" },\r
- { "File Access: Movies Folder (Read/Write)", "assets.movies.read-write" }\r
+ { "File Access: Movies Folder (Read/Write)", "assets.movies.read-write" },\r
+\r
+ { "Temporary Exception: Audio Unit Hosting", "temporary-exception.audio-unit-host" },\r
+ { "Temporary Exception: Global Mach Service", "temporary-exception.mach-lookup.global-name" },\r
+ { "Temporary Exception: Global Mach Service Dynamic Registration", "temporary-exception.mach-register.global-name" },\r
+ { "Temporary Exception: Home Directory File Access (Read Only)", "temporary-exception.files.home-relative-path.read-only" },\r
+ { "Temporary Exception: Home Directory File Access (Read/Write)", "temporary-exception.files.home-relative-path.read-write" },\r
+ { "Temporary Exception: Absolute Path File Access (Read Only)", "temporary-exception.files.absolute-path.read-only" },\r
+ { "Temporary Exception: Absolute Path File Access (Read/Write)", "temporary-exception.files.absolute-path.read-write" },\r
+ { "Temporary Exception: IOKit User Client Class", "temporary-exception.iokit-user-client-class" },\r
+ { "Temporary Exception: Shared Preference Domain (Read Only)", "temporary-exception.shared-preference.read-only" },\r
+ { "Temporary Exception: Shared Preference Domain (Read/Write)", "temporary-exception.shared-preference.read-write" }\r
};\r
\r
StringArray sandboxKeys;\r
\r
props.add (new TextPropertyComponent (subprojectsValue, "Xcode Subprojects", 8192, true),\r
"Paths to Xcode projects that should be added to the build (one per line). "\r
- "The names of the required build products can be specified after a colon, comma seperated, "\r
+ "The names of the required build products can be specified after a colon, comma separated, "\r
"e.g. \"path/to/MySubProject.xcodeproj: MySubProject, OtherTarget\". "\r
"If no build products are specified, all build products associated with a subproject will be added.");\r
\r
//==============================================================================\r
void createConfigProperties (PropertyListBuilder& props) override\r
{\r
- addXcodePluginInstallPathProperties (props);\r
+ if (project.isAudioPluginProject())\r
+ addXcodePluginInstallPathProperties (props);\r
+\r
addRecommendedLLVMCompilerWarningsProperty (props);\r
addGCCOptimisationProperty (props);\r
\r
{\r
props.add (new ChoicePropertyComponent (osxSDKVersion, "OSX Base SDK Version", getSDKChoiceList<StringArray> (oldestSDKVersion, true),\r
getSDKChoiceList<Array<var>> (oldestSDKVersion, true)),\r
- "The version of OSX to link against in the Xcode build. If \"Default\" is selected then the field will be left "\r
- "empty and the Xcode default will be used.");\r
+ "The version of the macOS SDK to link against. If \"Default\" is selected then the Xcode default will be used.");\r
\r
props.add (new ChoicePropertyComponent (osxDeploymentTarget, "OSX Deployment Target", getSDKChoiceList<StringArray> (oldestDeploymentTarget, false),\r
getSDKChoiceList<Array<var>> (oldestDeploymentTarget, true)),\r
\r
props.add (new ChoicePropertyComponent (stripLocalSymbolsEnabled, "Strip Local Symbols"),\r
"Enable this to strip any locally defined symbols resulting in a smaller binary size. Enabling this "\r
- "will also remove any function names from crash logs. Must be disabled for static library projects.");\r
+ "will also remove any function names from crash logs. Must be disabled for static library projects. "\r
+ "Note that disabling this will not necessarily generate full debug symbols. For release configs, "\r
+ "you will also need to add the following to the \"Custom Xcode Flags\" field: "\r
+ "GCC_GENERATE_DEBUGGING_SYMBOLS = YES, STRIP_INSTALLED_PRODUCT = NO, COPY_PHASE_STRIP = NO");\r
}\r
\r
String getModuleLibraryArchName() const override\r
return String ("Info-") + String (getName()).replace (" ", "_") + String (".plist");\r
}\r
\r
+ String getEntitlementsFilename() const\r
+ {\r
+ return String (getName()).replace (" ", "_") + String (".entitlements");\r
+ }\r
+\r
String xcodePackageType, xcodeBundleSignature, xcodeBundleExtension;\r
String xcodeProductType, xcodeFileType;\r
String xcodeOtherRezFlags, xcodeBundleIDSubPath;\r
{\r
Array<SourceFileInfo> result;\r
\r
- auto targetType = (owner.getProject().getProjectType().isAudioPlugin() ? type : SharedCodeTarget);\r
+ auto targetType = (owner.getProject().isAudioPluginProject() ? type : SharedCodeTarget);\r
\r
if (projectItem.isGroup())\r
{\r
|| (owner.isiOS() && owner.isiCloudPermissionsEnabled()))\r
return true;\r
\r
- if (owner.project.getProjectType().isAudioPlugin()\r
- && ( (owner.isOSX() && type == Target::AudioUnitv3PlugIn)\r
+ if (owner.project.isAudioPluginProject()\r
+ && ((owner.isOSX() && type == Target::AudioUnitv3PlugIn)\r
|| (owner.isiOS() && type == Target::StandalonePlugIn && owner.getProject().shouldEnableIAA())))\r
return true;\r
\r
// the aggregate target needs to have the deployment target set for\r
// pre-/post-build scripts\r
s.set ("MACOSX_DEPLOYMENT_TARGET", getOSXDeploymentTarget (config.getOSXDeploymentTargetString()));\r
-\r
- auto sdkRoot = getOSXSDKVersion (config.getOSXSDKVersionString());\r
-\r
- if (sdkRoot.isNotEmpty())\r
- s.set ("SDKROOT", sdkRoot);\r
+ s.set ("SDKROOT", getOSXSDKVersion (config.getOSXSDKVersionString()));\r
\r
return s;\r
}\r
else\r
{\r
s.set ("MACOSX_DEPLOYMENT_TARGET", getOSXDeploymentTarget (config.getOSXDeploymentTargetString()));\r
-\r
- auto sdkRoot = getOSXSDKVersion (config.getOSXSDKVersionString());\r
-\r
- if (sdkRoot.isNotEmpty())\r
- s.set ("SDKROOT", sdkRoot);\r
}\r
\r
s.set ("GCC_VERSION", gccVersion);\r
s.set ("DEVELOPMENT_TEAM", owner.getDevelopmentTeamIDString());\r
\r
if (shouldAddEntitlements())\r
- s.set ("CODE_SIGN_ENTITLEMENTS", owner.getEntitlementsFileName().quoted());\r
+ s.set ("CODE_SIGN_ENTITLEMENTS", getEntitlementsFilename().quoted());\r
\r
{\r
auto cppStandard = owner.project.getCppStandardString();\r
librarySearchPaths.add (owner.getSearchPathForStaticLibrary (lib));\r
}\r
\r
- if (owner.project.getProjectType().isAudioPlugin())\r
+ if (owner.project.isAudioPluginProject())\r
{\r
if (owner.getTargetOfType (Target::SharedCodeTarget) != nullptr)\r
{\r
" -I \\\"$(DEVELOPER_DIR)/Extras/CoreAudio/AudioUnits/AUPublic/AUBase\\\""\r
" -I \\\"$(DEVELOPER_DIR)/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/System/Library/Frameworks/AudioUnit.framework/Headers\\\"";\r
\r
- xcodeFrameworks.addTokens ("AudioUnit CoreAudioKit", false);\r
+ xcodeFrameworks.addArray ({ "AudioUnit", "CoreAudioKit" });\r
\r
XmlElement plistKey ("key");\r
plistKey.addTextElement ("AudioComponents");\r
\r
void addExtraAudioUnitv3PlugInTargetSettings()\r
{\r
- if (owner.isiOS())\r
- xcodeFrameworks.addTokens ("CoreAudioKit AVFoundation", false);\r
- else\r
- xcodeFrameworks.addTokens ("AudioUnit CoreAudioKit AVFoundation", false);\r
+ xcodeFrameworks.addArray ({ "AVFoundation", "CoreAudioKit" });\r
+\r
+ if (owner.isOSX())\r
+ xcodeFrameworks.add ("AudioUnit");\r
\r
XmlElement plistKey ("key");\r
plistKey.addTextElement ("NSExtension");\r
return getVersionName (minVersion);\r
}\r
\r
- String getOSXSDKVersion (const String& sdkVersion) const\r
- {\r
- for (int v = oldestSDKVersion; v <= currentSDKVersion; ++v)\r
- if (sdkVersion == getSDKDisplayName (v))\r
- return getSDKRootName (v);\r
-\r
- return {};\r
- }\r
-\r
//==============================================================================\r
const XcodeProjectExporter& owner;\r
\r
postbuildCommandValue, prebuildCommandValue,\r
duplicateAppExResourcesFolderValue, iosDeviceFamilyValue, iPhoneScreenOrientationValue,\r
iPadScreenOrientationValue, customXcodeResourceFoldersValue, customXcassetsFolderValue,\r
- appSandboxValue, appSandboxOptionsValue,\r
+ appSandboxValue, appSandboxInheritanceValue, appSandboxOptionsValue,\r
hardenedRuntimeValue, hardenedRuntimeOptionsValue,\r
microphonePermissionNeededValue, microphonePermissionsTextValue, cameraPermissionNeededValue, cameraPermissionTextValue, iosBluetoothPermissionNeededValue, iosBluetoothPermissionTextValue,\r
uiFileSharingEnabledValue, uiSupportsDocumentBrowserValue, uiStatusBarHiddenValue, documentExtensionsValue, iosInAppPurchasesValue,\r
\r
void addFilesAndGroupsToProject (StringArray& topLevelGroupIDs) const\r
{\r
- addEntitlementsFile();\r
+ for (auto* target : targets)\r
+ addEntitlementsFile (*target);\r
\r
for (auto& group : getAllGroups())\r
{\r
auto sourceFiles = target->sourceIDs;\r
\r
if (target->type == XcodeTarget::SharedCodeTarget\r
- || (! project.getProjectType().isAudioPlugin()))\r
+ || (! project.isAudioPluginProject()))\r
sourceFiles.addArray (sourceIDs);\r
\r
target->addBuildPhase ("PBXSourcesBuildPhase", sourceFiles);\r
\r
target->addShellScriptBuildPhase ("Post-build script", getPostBuildScript());\r
\r
- if (project.getProjectType().isAudioPlugin() && project.shouldBuildAUv3()\r
+ if (project.isAudioPluginProject() && project.shouldBuildAUv3()\r
&& project.shouldBuildStandalonePlugin() && target->type == XcodeTarget::StandalonePlugIn)\r
embedAppExtension();\r
\r
- if (project.getProjectType().isAudioPlugin() && project.shouldBuildUnityPlugin()\r
+ if (project.isAudioPluginProject() && project.shouldBuildUnityPlugin()\r
&& target->type == XcodeTarget::UnityPlugIn)\r
embedUnityScript();\r
\r
{\r
StringArray dependencies;\r
\r
- if (project.getProjectType().isAudioPlugin())\r
+ if (project.isAudioPluginProject())\r
{\r
if (target.type == XcodeTarget::StandalonePlugIn) // depends on AUv3 and shared code\r
{\r
s.set ("TARGETED_DEVICE_FAMILY", getDeviceFamilyString().quoted());\r
s.set ("IPHONEOS_DEPLOYMENT_TARGET", config.getiOSDeploymentTargetString());\r
}\r
+ else\r
+ {\r
+ s.set ("SDKROOT", getOSXSDKVersion (config.getOSXSDKVersionString()));\r
+ }\r
\r
s.set ("ZERO_LINK", "NO");\r
\r
s.removeDuplicates (true);\r
s.sort (true);\r
\r
+ // When building against the 10.15 SDK we need to make sure the\r
+ // AudioUnit framework is linked before the AudioToolbox framework.\r
+ auto audioUnitIndex = s.indexOf ("AudioUnit", false, 1);\r
+\r
+ if (audioUnitIndex != -1)\r
+ {\r
+ s.remove (audioUnitIndex);\r
+ s.insert (0, "AudioUnit");\r
+ }\r
+\r
for (auto& framework : s)\r
{\r
auto frameworkID = addFramework (framework);\r
return {};\r
}\r
\r
- String getEntitlementsFileName() const\r
- {\r
- return project.getProjectFilenameRootString() + String (".entitlements");\r
- }\r
-\r
- StringPairArray getEntitlements() const\r
+ StringPairArray getEntitlements (XcodeTarget& target) const\r
{\r
StringPairArray entitlements;\r
\r
- if (project.getProjectType().isAudioPlugin())\r
+ if (project.isAudioPluginProject())\r
{\r
- if (isiOS())\r
- {\r
- if (project.shouldEnableIAA())\r
- entitlements.set ("inter-app-audio", "<true/>");\r
- }\r
- else\r
- {\r
- entitlements.set ("com.apple.security.app-sandbox", "<true/>");\r
- }\r
+ if (isiOS() && project.shouldEnableIAA())\r
+ entitlements.set ("inter-app-audio", "<true/>");\r
}\r
else\r
{\r
for (auto& option : getHardenedRuntimeOptions())\r
entitlements.set (option, "<true/>");\r
\r
- if (isAppSandboxEnabled())\r
- for (auto& option : getAppSandboxOptions())\r
- entitlements.set (option, "<true/>");\r
+ if (isAppSandboxEnabled() || (project.isAudioPluginProject() && target.type == XcodeTarget::AudioUnitv3PlugIn))\r
+ {\r
+ entitlements.set ("com.apple.security.app-sandbox", "<true/>");\r
+\r
+ if (isAppSandboxInhertianceEnabled())\r
+ {\r
+ // no other sandbox options can be specified if sandbox inheritance is enabled!\r
+ jassert (getAppSandboxOptions().isEmpty());\r
+\r
+ entitlements.set ("com.apple.security.inherit", "<true/>");\r
+ }\r
+\r
+ if (isAppSandboxEnabled())\r
+ for (auto& option : getAppSandboxOptions())\r
+ entitlements.set (option, "<true/>");\r
+ }\r
\r
if (isiOS() && isiCloudPermissionsEnabled())\r
{\r
return entitlements;\r
}\r
\r
- String addEntitlementsFile() const\r
+ void addEntitlementsFile (XcodeTarget& target) const\r
{\r
- String content =\r
- "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"\r
- "<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n"\r
- "<plist version=\"1.0\">\n"\r
- "<dict>\n";\r
-\r
- auto entitlements = getEntitlements();\r
- auto keys = entitlements.getAllKeys();\r
+ auto entitlements = getEntitlements (target);\r
\r
- for (auto& key : keys)\r
+ if (entitlements.size() > 0)\r
{\r
- content += "\t<key>" + key + "</key>\n"\r
- "\t" + entitlements[key] + "\n";\r
- }\r
- content += "</dict>\n"\r
- "</plist>\n";\r
+ String content =\r
+ "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"\r
+ "<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n"\r
+ "<plist version=\"1.0\">\n"\r
+ "<dict>\n";\r
\r
- auto entitlementsFile = getTargetFolder().getChildFile (getEntitlementsFileName());\r
- overwriteFileIfDifferentOrThrow (entitlementsFile, content);\r
+ for (auto& key : entitlements.getAllKeys())\r
+ content += "\t<key>" + key + "</key>\n"\r
+ "\t" + entitlements[key] + "\n";\r
\r
- RelativePath plistPath (entitlementsFile, getTargetFolder(), RelativePath::buildTargetFolder);\r
- return addFile (plistPath, false, false, false, false, nullptr, {});\r
+ content += "</dict>\n"\r
+ "</plist>\n";\r
+\r
+ auto entitlementsFile = getTargetFolder().getChildFile (target.getEntitlementsFilename());\r
+ overwriteFileIfDifferentOrThrow (entitlementsFile, content);\r
+\r
+ RelativePath entitlementsPath (entitlementsFile, getTargetFolder(), RelativePath::buildTargetFolder);\r
+ addFile (entitlementsPath, false, false, false, false, nullptr, {});\r
+ }\r
}\r
\r
String addProjectItem (const Project::Item& projectItem) const\r
\r
auto projectRootHash = project.getProjectRoot().toXmlString().hashCode();\r
\r
- if (project.getProjectType().isAudioPlugin())\r
+ if (project.isAudioPluginProject())\r
{\r
writePluginCharacteristicsFile();\r
\r
\r
if (errors.size() == 0)\r
{\r
- // Workaround for a bug where Xcode thinks the project is invalid if opened immedietely\r
+ // Workaround for a bug where Xcode thinks the project is invalid if opened immediately\r
// after writing\r
if (waitAfterSaving)\r
Thread::sleep (2000);\r
\r
if (errors.size() == 0)\r
{\r
- if (project.getProjectType().isAudioPlugin())\r
+ if (project.isAudioPluginProject())\r
writePluginCharacteristicsFile();\r
\r
writeAppConfigFile (modules, loadUserContentFromAppConfig());\r
return longest;\r
}\r
\r
- File getAppConfigFile() const { return generatedCodeFolder.getChildFile (project.getAppConfigFilename()); }\r
+ File getAppConfigFile() const { return generatedCodeFolder.getChildFile (Project::getAppConfigFilename()); }\r
\r
String loadUserContentFromAppConfig() const\r
{\r
mem.setNewLineString (projectLineFeed);\r
\r
writeAppConfig (mem, modules, userContent);\r
- saveGeneratedFile (project.getAppConfigFilename(), mem);\r
+ saveGeneratedFile (Project::getAppConfigFilename(), mem);\r
}\r
\r
void writeAppHeader (MemoryOutputStream& out, const OwnedArray<LibraryModule>& modules)\r
out << "#pragma once" << newLine << newLine;\r
\r
if (appConfigFile.exists())\r
- out << CodeHelpers::createIncludeStatement (project.getAppConfigFilename()) << newLine;\r
+ out << CodeHelpers::createIncludeStatement (Project::getAppConfigFilename()) << newLine;\r
\r
if (modules.size() > 0)\r
{\r
mem.setNewLineString (projectLineFeed);\r
\r
writeAppHeader (mem, modules);\r
- saveGeneratedFile (project.getJuceSourceHFilename(), mem);\r
+ saveGeneratedFile (Project::getJuceSourceHFilename(), mem);\r
}\r
\r
void writeModuleCppWrappers (const OwnedArray<LibraryModule>& modules)\r
\r
mem << "*/" << newLine\r
<< newLine\r
- << "#include " << project.getAppConfigFilename().quoted() << newLine\r
+ << "#include " << Project::getAppConfigFilename().quoted() << newLine\r
<< "#include <";\r
\r
if (cu.file.getFileExtension() != ".r") // .r files are included without the path\r
}\r
else if (key == Ids::androidSDKPath)\r
{\r
- return (os == TargetOS::linux ? "${user.home}/Android/Sdk" :\r
- "${user.home}/Library/Android/sdk");\r
+ if (os == TargetOS::windows) return "${user.home}\\AppData\\Local\\Android\\Sdk";\r
+ else if (os == TargetOS::osx) return "${user.home}/Library/Android/sdk";\r
+ else if (os == TargetOS::linux) return "${user.home}/Android/Sdk";\r
+\r
+ jassertfalse;\r
+ return {};\r
}\r
else if (key == Ids::androidNDKPath)\r
{\r
- return getFallbackPathForOS (Ids::androidSDKPath, os) + "/ndk-bundle";\r
+ return getFallbackPathForOS (Ids::androidSDKPath, os) + File::getSeparatorChar() + "ndk-bundle";\r
}\r
else if (key == Ids::clionExePath)\r
{\r
return "#include \"" + includePath + "\"";\r
}\r
\r
+ String createIncludePathIncludeStatement (const String& includedFilename)\r
+ {\r
+ return "#include <" + includedFilename + ">";\r
+ }\r
+\r
String makeBinaryDataIdentifierName (const File& file)\r
{\r
return makeValidIdentifier (file.getFileName()\r
String unindent (const String& code, int numSpaces);\r
String makeValidIdentifier (String s, bool capitalise, bool removeColons,\r
bool allowTemplates, bool allowAsterisks = false);\r
+ String makeBinaryDataIdentifierName (const File& file);\r
+\r
String createIncludeStatement (const File& includedFile, const File& targetFile);\r
String createIncludeStatement (const String& includePath);\r
- String makeBinaryDataIdentifierName (const File& file);\r
+ String createIncludePathIncludeStatement (const String& includedFilename);\r
\r
String stringLiteral (const String& text, int maxLineLength = -1);\r
String floatLiteral (double value, int numDecPlaces);\r
DECLARE_ID (useLocalCopy);\r
DECLARE_ID (overwriteOnSave);\r
DECLARE_ID (appSandbox);\r
+ DECLARE_ID (appSandboxInheritance);\r
DECLARE_ID (appSandboxOptions);\r
DECLARE_ID (hardenedRuntime);\r
DECLARE_ID (hardenedRuntimeOptions);\r
--- /dev/null
+/*\r
+ ==============================================================================\r
+\r
+ This file is part of the JUCE library.\r
+ Copyright (c) 2017 - ROLI Ltd.\r
+\r
+ JUCE is an open source library subject to commercial or open-source\r
+ licensing.\r
+\r
+ By using JUCE, you agree to the terms of both the JUCE 5 End-User License\r
+ Agreement and JUCE 5 Privacy Policy (both updated and effective as of the\r
+ 27th April 2017).\r
+\r
+ End User License Agreement: www.juce.com/juce-5-licence\r
+ Privacy Policy: www.juce.com/juce-5-privacy-policy\r
+\r
+ Or: You may also use this code under the terms of the GPL v3 (see\r
+ www.gnu.org/licenses).\r
+\r
+ JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER\r
+ EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE\r
+ DISCLAIMED.\r
+\r
+ ==============================================================================\r
+*/\r
+\r
+#include "../../Application/jucer_Headers.h"\r
+#include "jucer_VersionInfo.h"\r
+\r
+std::unique_ptr<VersionInfo> VersionInfo::fetchFromUpdateServer (const String& versionString)\r
+{\r
+ return fetch ("tags/" + versionString);\r
+}\r
+\r
+std::unique_ptr<VersionInfo> VersionInfo::fetchLatestFromUpdateServer()\r
+{\r
+ return fetch ("latest");\r
+}\r
+\r
+std::unique_ptr<InputStream> VersionInfo::createInputStreamForAsset (const Asset& asset, int& statusCode)\r
+{\r
+ URL downloadUrl (asset.url);\r
+ StringPairArray responseHeaders;\r
+\r
+ return std::unique_ptr<InputStream> (downloadUrl.createInputStream (false, nullptr, nullptr,\r
+ "Accept: application/octet-stream",\r
+ 0, &responseHeaders, &statusCode, 1));\r
+}\r
+\r
+bool VersionInfo::isNewerVersionThanCurrent()\r
+{\r
+ jassert (versionString.isNotEmpty());\r
+\r
+ auto currentTokens = StringArray::fromTokens (ProjectInfo::versionString, ".", {});\r
+ auto thisTokens = StringArray::fromTokens (versionString, ".", {});\r
+\r
+ jassert (thisTokens.size() == 3 && thisTokens.size() == 3);\r
+\r
+ if (currentTokens[0].getIntValue() == thisTokens[0].getIntValue())\r
+ {\r
+ if (currentTokens[1].getIntValue() == thisTokens[1].getIntValue())\r
+ return currentTokens[2].getIntValue() < thisTokens[2].getIntValue();\r
+\r
+ return currentTokens[1].getIntValue() < thisTokens[1].getIntValue();\r
+ }\r
+\r
+ return currentTokens[0].getIntValue() < thisTokens[0].getIntValue();\r
+}\r
+\r
+std::unique_ptr<VersionInfo> VersionInfo::fetch (const String& endpoint)\r
+{\r
+ URL latestVersionURL ("https://api.github.com/repos/WeAreROLI/JUCE/releases/" + endpoint);\r
+ std::unique_ptr<InputStream> inStream (latestVersionURL.createInputStream (false));\r
+\r
+ if (inStream == nullptr)\r
+ return nullptr;\r
+\r
+ auto content = inStream->readEntireStreamAsString();\r
+ auto latestReleaseDetails = JSON::parse (content);\r
+\r
+ auto* json = latestReleaseDetails.getDynamicObject();\r
+\r
+ if (json == nullptr)\r
+ return nullptr;\r
+\r
+ auto versionString = json->getProperty ("tag_name").toString();\r
+\r
+ if (versionString.isEmpty())\r
+ return nullptr;\r
+\r
+ auto* assets = json->getProperty ("assets").getArray();\r
+\r
+ if (assets == nullptr)\r
+ return nullptr;\r
+\r
+ auto releaseNotes = json->getProperty ("body").toString();\r
+ std::vector<VersionInfo::Asset> parsedAssets;\r
+\r
+ for (auto& asset : *assets)\r
+ {\r
+ if (auto* assetJson = asset.getDynamicObject())\r
+ {\r
+ parsedAssets.push_back ({ assetJson->getProperty ("name").toString(),\r
+ assetJson->getProperty ("url").toString() });\r
+ jassert (parsedAssets.back().name.isNotEmpty());\r
+ jassert (parsedAssets.back().url.isNotEmpty());\r
+ }\r
+ else\r
+ {\r
+ jassertfalse;\r
+ }\r
+ }\r
+\r
+ return std::unique_ptr<VersionInfo> (new VersionInfo ({ versionString, releaseNotes, std::move (parsedAssets) }));\r
+}\r
--- /dev/null
+/*\r
+ ==============================================================================\r
+\r
+ This file is part of the JUCE library.\r
+ Copyright (c) 2017 - ROLI Ltd.\r
+\r
+ JUCE is an open source library subject to commercial or open-source\r
+ licensing.\r
+\r
+ By using JUCE, you agree to the terms of both the JUCE 5 End-User License\r
+ Agreement and JUCE 5 Privacy Policy (both updated and effective as of the\r
+ 27th April 2017).\r
+\r
+ End User License Agreement: www.juce.com/juce-5-licence\r
+ Privacy Policy: www.juce.com/juce-5-privacy-policy\r
+\r
+ Or: You may also use this code under the terms of the GPL v3 (see\r
+ www.gnu.org/licenses).\r
+\r
+ JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER\r
+ EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE\r
+ DISCLAIMED.\r
+\r
+ ==============================================================================\r
+*/\r
+\r
+#pragma once\r
+\r
+\r
+//==============================================================================\r
+class VersionInfo\r
+{\r
+public:\r
+ struct Asset\r
+ {\r
+ const String name;\r
+ const String url;\r
+ };\r
+\r
+ static std::unique_ptr<VersionInfo> fetchFromUpdateServer (const String& versionString);\r
+ static std::unique_ptr<VersionInfo> fetchLatestFromUpdateServer();\r
+ static std::unique_ptr<InputStream> createInputStreamForAsset (const Asset& asset, int& statusCode);\r
+\r
+ bool isNewerVersionThanCurrent();\r
+\r
+ const String versionString;\r
+ const String releaseNotes;\r
+ const std::vector<Asset> assets;\r
+\r
+private:\r
+ VersionInfo() = default;\r
+\r
+ static std::unique_ptr<VersionInfo> fetch (const String&);\r
+};\r
{\r
String mainTemplate (BinaryData::jucer_PIPMain_cpp);\r
\r
- mainTemplate = mainTemplate.replace ("%%filename%%", useLocalCopy ? pipFile.getFileName()\r
- : isTemp ? pipFile.getFullPathName()\r
- : RelativePath (pipFile, outputDirectory.getChildFile ("Source"),\r
- RelativePath::unknown).toUnixStyle());\r
+ auto includeFilename = [&]\r
+ {\r
+ if (useLocalCopy) return pipFile.getFileName();\r
+ if (isTemp) return pipFile.getFullPathName();\r
+\r
+ return RelativePath (pipFile, outputDirectory.getChildFile ("Source"), RelativePath::unknown).toUnixStyle();\r
+ }();\r
+\r
+ mainTemplate = mainTemplate.replace ("%%filename%%", includeFilename)\r
+ .replace ("%%include_juce%%", CodeHelpers::createIncludePathIncludeStatement (Project::getJuceSourceHFilename()));\r
\r
auto type = metadata[Ids::type].toString();\r
\r
{\r
public:\r
FilePathPropertyComponent (Value valueToControl, const String& propertyName, bool isDir, bool thisOS = true,\r
- const String& wildcardsToUse = "*", const File& relativeRoot = File(), bool multiPath = false)\r
+ const String& wildcardsToUse = "*", const File& relativeRoot = File())\r
: PropertyComponent (propertyName),\r
text (valueToControl, propertyName, 1024, false),\r
- isDirectory (isDir), isThisOS (thisOS), supportsMultiplePaths (multiPath), wildcards (wildcardsToUse), root (relativeRoot)\r
+ isDirectory (isDir), isThisOS (thisOS), wildcards (wildcardsToUse), root (relativeRoot)\r
{\r
textValue.referTo (valueToControl);\r
-\r
init();\r
}\r
\r
/** Displays a default value when no value is specified by the user. */\r
FilePathPropertyComponent (ValueWithDefault& valueToControl, const String& propertyName, bool isDir, bool thisOS = true,\r
- const String& wildcardsToUse = "*", const File& relativeRoot = File(), bool multiPath = false)\r
+ const String& wildcardsToUse = "*", const File& relativeRoot = File())\r
: PropertyComponent (propertyName),\r
text (valueToControl, propertyName, 1024, false),\r
- isDirectory (isDir), isThisOS (thisOS), supportsMultiplePaths (multiPath), wildcards (wildcardsToUse), root (relativeRoot)\r
+ isDirectory (isDir), isThisOS (thisOS), wildcards (wildcardsToUse), root (relativeRoot)\r
{\r
textValue = valueToControl.getPropertyAsValue();\r
-\r
init();\r
}\r
\r
\r
void filesDropped (const StringArray& selectedFiles, int, int) override\r
{\r
- if (supportsMultiplePaths)\r
- {\r
- for (auto& f : selectedFiles)\r
- setTo (f);\r
- }\r
- else\r
- {\r
- setTo (selectedFiles[0]);\r
- }\r
+\r
+ setTo (selectedFiles[0]);\r
\r
highlightForDragAndDrop = false;\r
repaint();\r
auto pathName = (root == File()) ? f.getFullPathName()\r
: f.getRelativePathFrom (root);\r
\r
- auto currentPath = text.getText();\r
-\r
- if (supportsMultiplePaths && currentPath.isNotEmpty())\r
- pathName = currentPath.trimCharactersAtEnd (" ;") + "; " + pathName;\r
-\r
text.setText (pathName);\r
updateEditorColour();\r
}\r
\r
void updateEditorColour()\r
{\r
- if (supportsMultiplePaths || ! isThisOS)\r
- return;\r
-\r
- text.setColour (TextPropertyComponent::textColourId, findColour (widgetTextColourId));\r
+ if (isThisOS)\r
+ {\r
+ text.setColour (TextPropertyComponent::textColourId, findColour (widgetTextColourId));\r
\r
- auto pathToCheck = text.getText();\r
+ auto pathToCheck = text.getText();\r
\r
- if (pathToCheck.isNotEmpty())\r
- {\r
- pathToCheck.replace ("${user.home}", "~");\r
+ if (pathToCheck.isNotEmpty())\r
+ {\r
+ pathToCheck.replace ("${user.home}", "~");\r
\r
- #if JUCE_WINDOWS\r
- if (pathToCheck.startsWith ("~"))\r
- pathToCheck = pathToCheck.replace ("~", File::getSpecialLocation (File::userHomeDirectory).getFullPathName());\r
- #endif\r
+ #if JUCE_WINDOWS\r
+ if (pathToCheck.startsWith ("~"))\r
+ pathToCheck = pathToCheck.replace ("~", File::getSpecialLocation (File::userHomeDirectory).getFullPathName());\r
+ #endif\r
\r
- if (! root.getChildFile (pathToCheck).exists())\r
- text.setColour (TextPropertyComponent::textColourId, Colours::red);\r
+ if (! root.getChildFile (pathToCheck).exists())\r
+ text.setColour (TextPropertyComponent::textColourId, Colours::red);\r
+ }\r
}\r
}\r
\r
TextPropertyComponent text;\r
TextButton browseButton { "..." };\r
\r
- bool isDirectory, isThisOS, supportsMultiplePaths, highlightForDragAndDrop = false;\r
+ bool isDirectory, isThisOS, highlightForDragAndDrop = false;\r
String wildcards;\r
File root;\r
\r
{\r
auto content = fillInBasicTemplateFields (newFile, parent, templateName)\r
.replace ("%%component_class%%", className)\r
- .replace ("%%include_juce%%", CodeHelpers::createIncludeStatement (parent.project.getAppIncludeFile(), newFile));\r
+ .replace ("%%include_juce%%", CodeHelpers::createIncludePathIncludeStatement (Project::getJuceSourceHFilename()));\r
\r
content = replaceLineFeeds (content, parent.project.getProjectLineFeed());\r
\r
addAndMakeVisible (modulesLabel);\r
modulesLabel.attachToComponent (¤tPathBox, true);\r
\r
- addAndMakeVisible (useGlobalPathsToggle);\r
- useGlobalPathsToggle.setToggleState (true, sendNotification);\r
- useGlobalPathsToggle.onClick = [this]\r
+ auto updateEnablement = [this]\r
{\r
isUsingGlobalPaths = useGlobalPathsToggle.getToggleState();\r
\r
openFolderButton.setEnabled (! isUsingGlobalPaths);\r
modulesLabel.setEnabled (! isUsingGlobalPaths);\r
};\r
+\r
+ addAndMakeVisible (useGlobalPathsToggle);\r
+ useGlobalPathsToggle.setToggleState (true, sendNotification);\r
+ useGlobalPathsToggle.onClick = [updateEnablement] { updateEnablement(); };\r
+\r
+ updateEnablement();\r
}\r
\r
void resized() override\r
return;\r
\r
if (modulesPathBox.isUsingGlobalPaths)\r
+ {\r
getAppSettings().getStoredPath (Ids::defaultJuceModulePath, TargetOS::getThisOS()).setValue (wizard->modulesFolder.getFullPathName(), nullptr);\r
+ ProjucerApplication::getApp().rescanJUCEPathModules();\r
+ }\r
}\r
\r
auto projectDir = fileBrowser.getSelectedFile (0);\r
\r
if (project != nullptr)\r
{\r
- mw->setProject (project.release());\r
+ mw->setProject (std::move (project));\r
getAppSettings().lastWizardFolder = projectDir.getParentDirectory();\r
}\r
}\r
\r
setExecutableNameForAllTargets (project, File::createLegalFileName (appTitle));\r
\r
- String appHeaders (CodeHelpers::createIncludeStatement (project.getAppIncludeFile(), mainCppFile));\r
+ auto juceHeaderInclude = CodeHelpers::createIncludePathIncludeStatement (Project::getJuceSourceHFilename());\r
+ auto appHeaders = juceHeaderInclude + newLine + CodeHelpers::createIncludeStatement (contentCompH, mainCppFile);\r
\r
// create main window\r
- appHeaders << newLine << CodeHelpers::createIncludeStatement (contentCompH, mainCppFile);\r
-\r
String windowH = project.getFileTemplate (createCppFile ? "jucer_AnimatedComponentTemplate_h"\r
: "jucer_AnimatedComponentSimpleTemplate_h")\r
- .replace ("%%include_juce%%", CodeHelpers::createIncludeStatement (project.getAppIncludeFile(), contentCompH), false)\r
+ .replace ("%%include_juce%%", juceHeaderInclude)\r
.replace ("%%content_component_class%%", contentCompName, false);\r
\r
if (! FileHelpers::overwriteFileWithNewDataIfDifferent (contentCompH, windowH))\r
if (createCppFile)\r
{\r
String windowCpp = project.getFileTemplate ("jucer_AnimatedComponentTemplate_cpp")\r
- .replace ("%%include_juce%%", CodeHelpers::createIncludeStatement (project.getAppIncludeFile(), contentCompCpp), false)\r
+ .replace ("%%include_juce%%", juceHeaderInclude)\r
.replace ("%%include_corresponding_header%%", CodeHelpers::createIncludeStatement (contentCompH, contentCompCpp), false)\r
.replace ("%%content_component_class%%", contentCompName, false);\r
\r
\r
setExecutableNameForAllTargets (project, File::createLegalFileName (appTitle));\r
\r
- String appHeaders (CodeHelpers::createIncludeStatement (project.getAppIncludeFile(), mainCppFile));\r
+ auto juceHeaderInclude = CodeHelpers::createIncludePathIncludeStatement (Project::getJuceSourceHFilename());\r
+ auto appHeaders = juceHeaderInclude + newLine + CodeHelpers::createIncludeStatement (contentCompH, mainCppFile);\r
\r
// create main window\r
- appHeaders << newLine << CodeHelpers::createIncludeStatement (contentCompH, mainCppFile);\r
-\r
String windowH = project.getFileTemplate (createCppFile ? "jucer_AudioComponentTemplate_h"\r
: "jucer_AudioComponentSimpleTemplate_h")\r
- .replace ("%%include_juce%%", CodeHelpers::createIncludeStatement (project.getAppIncludeFile(), contentCompH), false)\r
+ .replace ("%%include_juce%%", juceHeaderInclude)\r
.replace ("%%content_component_class%%", contentCompName, false);\r
\r
if (! FileHelpers::overwriteFileWithNewDataIfDifferent (contentCompH, windowH))\r
if (createCppFile)\r
{\r
String windowCpp = project.getFileTemplate ("jucer_AudioComponentTemplate_cpp")\r
- .replace ("%%include_juce%%", CodeHelpers::createIncludeStatement (project.getAppIncludeFile(), contentCompCpp), false)\r
+ .replace ("%%include_juce%%", juceHeaderInclude)\r
.replace ("%%include_corresponding_header%%", CodeHelpers::createIncludeStatement (contentCompH, contentCompCpp), false)\r
.replace ("%%content_component_class%%", contentCompName, false);\r
\r
\r
setExecutableNameForAllTargets (project, File::createLegalFileName (appTitle));\r
\r
- String appHeaders (CodeHelpers::createIncludeStatement (project.getAppIncludeFile(), filterCppFile));\r
+ auto juceHeaderInclude = CodeHelpers::createIncludePathIncludeStatement (Project::getJuceSourceHFilename());\r
\r
String filterCpp = project.getFileTemplate ("jucer_AudioPluginFilterTemplate_cpp")\r
.replace ("%%filter_headers%%", CodeHelpers::createIncludeStatement (filterHFile, filterCppFile)\r
.replace ("%%editor_class_name%%", editorClassName, false);\r
\r
String filterH = project.getFileTemplate ("jucer_AudioPluginFilterTemplate_h")\r
- .replace ("%%app_headers%%", appHeaders, false)\r
+ .replace ("%%app_headers%%", juceHeaderInclude, false)\r
.replace ("%%filter_class_name%%", filterClassName, false);\r
\r
String editorCpp = project.getFileTemplate ("jucer_AudioPluginEditorTemplate_cpp")\r
.replace ("%%editor_class_name%%", editorClassName, false);\r
\r
String editorH = project.getFileTemplate ("jucer_AudioPluginEditorTemplate_h")\r
- .replace ("%%editor_headers%%", appHeaders + newLine + CodeHelpers::createIncludeStatement (filterHFile, filterCppFile), false)\r
+ .replace ("%%editor_headers%%", juceHeaderInclude + newLine + CodeHelpers::createIncludeStatement (filterHFile, filterCppFile), false)\r
.replace ("%%filter_class_name%%", filterClassName, false)\r
.replace ("%%editor_class_name%%", editorClassName, false);\r
\r
if (createMainCpp)\r
{\r
File mainCppFile = getSourceFilesFolder().getChildFile ("Main.cpp");\r
- String appHeaders (CodeHelpers::createIncludeStatement (project.getAppIncludeFile(), mainCppFile));\r
\r
String mainCpp = project.getFileTemplate ("jucer_MainConsoleAppTemplate_cpp")\r
- .replace ("%%app_headers%%", appHeaders, false);\r
+ .replace ("%%app_headers%%", CodeHelpers::createIncludePathIncludeStatement (Project::getJuceSourceHFilename()), false);\r
\r
if (! FileHelpers::overwriteFileWithNewDataIfDifferent (mainCppFile, mainCpp))\r
failedFiles.add (mainCppFile.getFullPathName());\r
\r
setExecutableNameForAllTargets (project, File::createLegalFileName (appTitle));\r
\r
- String appHeaders (CodeHelpers::createIncludeStatement (project.getAppIncludeFile(), mainCppFile));\r
+ auto juceHeaderInclude = CodeHelpers::createIncludePathIncludeStatement (Project::getJuceSourceHFilename());\r
+ auto appHeaders = juceHeaderInclude;\r
\r
if (createWindow)\r
{\r
\r
String windowH = project.getFileTemplate (createCppFile ? "jucer_ContentCompTemplate_h"\r
: "jucer_ContentCompSimpleTemplate_h")\r
- .replace ("%%include_juce%%", CodeHelpers::createIncludeStatement (project.getAppIncludeFile(), contentCompH), false)\r
+ .replace ("%%include_juce%%", juceHeaderInclude)\r
.replace ("%%content_component_class%%", contentCompName, false);\r
\r
if (! FileHelpers::overwriteFileWithNewDataIfDifferent (contentCompH, windowH))\r
if (createCppFile)\r
{\r
String windowCpp = project.getFileTemplate ("jucer_ContentCompTemplate_cpp")\r
- .replace ("%%include_juce%%", CodeHelpers::createIncludeStatement (project.getAppIncludeFile(), contentCompCpp), false)\r
+ .replace ("%%include_juce%%", juceHeaderInclude)\r
.replace ("%%include_corresponding_header%%", CodeHelpers::createIncludeStatement (contentCompH, contentCompCpp), false)\r
.replace ("%%content_component_class%%", contentCompName, false);\r
\r
\r
setExecutableNameForAllTargets (project, File::createLegalFileName (appTitle));\r
\r
- String appHeaders (CodeHelpers::createIncludeStatement (project.getAppIncludeFile(), mainCppFile));\r
+ auto juceHeaderInclude = CodeHelpers::createIncludePathIncludeStatement (Project::getJuceSourceHFilename());\r
+ auto appHeaders = juceHeaderInclude + newLine + CodeHelpers::createIncludeStatement (contentCompH, mainCppFile);\r
\r
// create main window\r
- appHeaders << newLine << CodeHelpers::createIncludeStatement (contentCompH, mainCppFile);\r
-\r
String windowH = project.getFileTemplate (createCppFile ? "jucer_OpenGLComponentTemplate_h"\r
: "jucer_OpenGLComponentSimpleTemplate_h")\r
- .replace ("%%include_juce%%", CodeHelpers::createIncludeStatement (project.getAppIncludeFile(), contentCompH), false)\r
+ .replace ("%%include_juce%%", juceHeaderInclude)\r
.replace ("%%content_component_class%%", contentCompName, false);\r
\r
if (! FileHelpers::overwriteFileWithNewDataIfDifferent (contentCompH, windowH))\r
if (createCppFile)\r
{\r
String windowCpp = project.getFileTemplate ("jucer_OpenGLComponentTemplate_cpp")\r
- .replace ("%%include_juce%%", CodeHelpers::createIncludeStatement (project.getAppIncludeFile(), contentCompCpp), false)\r
+ .replace ("%%include_juce%%", juceHeaderInclude)\r
.replace ("%%include_corresponding_header%%", CodeHelpers::createIncludeStatement (contentCompH, contentCompCpp), false)\r
.replace ("%%content_component_class%%", contentCompName, false);\r
\r
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+</dict>
+</plist>
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
-</dict>
-</plist>
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;
GCC_WARN_UNUSED_VARIABLE = YES;
ONLY_ACTIVE_ARCH = YES;
PRODUCT_NAME = "UnitTestRunner";
+ SDKROOT = macosx;
WARNING_CFLAGS = "-Wreorder";
ZERO_LINK = NO;
};
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
PRODUCT_NAME = "UnitTestRunner";
+ SDKROOT = macosx;
WARNING_CFLAGS = "-Wreorder";
ZERO_LINK = NO;
};
<ClCompile Include="..\..\..\..\modules\juce_core\misc\juce_RuntimePermissions.cpp">\r
<ExcludedFromBuild>true</ExcludedFromBuild>\r
</ClCompile>\r
- <ClCompile Include="..\..\..\..\modules\juce_core\misc\juce_StdFunctionCompat.cpp">\r
- <ExcludedFromBuild>true</ExcludedFromBuild>\r
- </ClCompile>\r
<ClCompile Include="..\..\..\..\modules\juce_core\misc\juce_Uuid.cpp">\r
<ExcludedFromBuild>true</ExcludedFromBuild>\r
</ClCompile>\r
<ClCompile Include="..\..\..\..\modules\juce_core\threads\juce_TimeSliceThread.cpp">\r
<ExcludedFromBuild>true</ExcludedFromBuild>\r
</ClCompile>\r
+ <ClCompile Include="..\..\..\..\modules\juce_core\threads\juce_WaitableEvent.cpp">\r
+ <ExcludedFromBuild>true</ExcludedFromBuild>\r
+ </ClCompile>\r
<ClCompile Include="..\..\..\..\modules\juce_core\time\juce_PerformanceCounter.cpp">\r
<ExcludedFromBuild>true</ExcludedFromBuild>\r
</ClCompile>\r
<ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_ConsoleApplication.h"/>\r
<ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_Result.h"/>\r
<ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_RuntimePermissions.h"/>\r
- <ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_StdFunctionCompat.h"/>\r
<ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_Uuid.h"/>\r
<ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_WindowsRegistry.h"/>\r
<ClInclude Include="..\..\..\..\modules\juce_core\native\juce_android_JNIHelpers.h"/>\r
<ClCompile Include="..\..\..\..\modules\juce_core\misc\juce_RuntimePermissions.cpp">\r
<Filter>JUCE Modules\juce_core\misc</Filter>\r
</ClCompile>\r
- <ClCompile Include="..\..\..\..\modules\juce_core\misc\juce_StdFunctionCompat.cpp">\r
- <Filter>JUCE Modules\juce_core\misc</Filter>\r
- </ClCompile>\r
<ClCompile Include="..\..\..\..\modules\juce_core\misc\juce_Uuid.cpp">\r
<Filter>JUCE Modules\juce_core\misc</Filter>\r
</ClCompile>\r
<ClCompile Include="..\..\..\..\modules\juce_core\threads\juce_TimeSliceThread.cpp">\r
<Filter>JUCE Modules\juce_core\threads</Filter>\r
</ClCompile>\r
+ <ClCompile Include="..\..\..\..\modules\juce_core\threads\juce_WaitableEvent.cpp">\r
+ <Filter>JUCE Modules\juce_core\threads</Filter>\r
+ </ClCompile>\r
<ClCompile Include="..\..\..\..\modules\juce_core\time\juce_PerformanceCounter.cpp">\r
<Filter>JUCE Modules\juce_core\time</Filter>\r
</ClCompile>\r
<ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_RuntimePermissions.h">\r
<Filter>JUCE Modules\juce_core\misc</Filter>\r
</ClInclude>\r
- <ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_StdFunctionCompat.h">\r
- <Filter>JUCE Modules\juce_core\misc</Filter>\r
- </ClInclude>\r
<ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_Uuid.h">\r
<Filter>JUCE Modules\juce_core\misc</Filter>\r
</ClInclude>\r
<ClCompile Include="..\..\..\..\modules\juce_core\misc\juce_RuntimePermissions.cpp">\r
<ExcludedFromBuild>true</ExcludedFromBuild>\r
</ClCompile>\r
- <ClCompile Include="..\..\..\..\modules\juce_core\misc\juce_StdFunctionCompat.cpp">\r
- <ExcludedFromBuild>true</ExcludedFromBuild>\r
- </ClCompile>\r
<ClCompile Include="..\..\..\..\modules\juce_core\misc\juce_Uuid.cpp">\r
<ExcludedFromBuild>true</ExcludedFromBuild>\r
</ClCompile>\r
<ClCompile Include="..\..\..\..\modules\juce_core\threads\juce_TimeSliceThread.cpp">\r
<ExcludedFromBuild>true</ExcludedFromBuild>\r
</ClCompile>\r
+ <ClCompile Include="..\..\..\..\modules\juce_core\threads\juce_WaitableEvent.cpp">\r
+ <ExcludedFromBuild>true</ExcludedFromBuild>\r
+ </ClCompile>\r
<ClCompile Include="..\..\..\..\modules\juce_core\time\juce_PerformanceCounter.cpp">\r
<ExcludedFromBuild>true</ExcludedFromBuild>\r
</ClCompile>\r
<ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_ConsoleApplication.h"/>\r
<ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_Result.h"/>\r
<ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_RuntimePermissions.h"/>\r
- <ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_StdFunctionCompat.h"/>\r
<ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_Uuid.h"/>\r
<ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_WindowsRegistry.h"/>\r
<ClInclude Include="..\..\..\..\modules\juce_core\native\juce_android_JNIHelpers.h"/>\r
<ClCompile Include="..\..\..\..\modules\juce_core\misc\juce_RuntimePermissions.cpp">\r
<Filter>JUCE Modules\juce_core\misc</Filter>\r
</ClCompile>\r
- <ClCompile Include="..\..\..\..\modules\juce_core\misc\juce_StdFunctionCompat.cpp">\r
- <Filter>JUCE Modules\juce_core\misc</Filter>\r
- </ClCompile>\r
<ClCompile Include="..\..\..\..\modules\juce_core\misc\juce_Uuid.cpp">\r
<Filter>JUCE Modules\juce_core\misc</Filter>\r
</ClCompile>\r
<ClCompile Include="..\..\..\..\modules\juce_core\threads\juce_TimeSliceThread.cpp">\r
<Filter>JUCE Modules\juce_core\threads</Filter>\r
</ClCompile>\r
+ <ClCompile Include="..\..\..\..\modules\juce_core\threads\juce_WaitableEvent.cpp">\r
+ <Filter>JUCE Modules\juce_core\threads</Filter>\r
+ </ClCompile>\r
<ClCompile Include="..\..\..\..\modules\juce_core\time\juce_PerformanceCounter.cpp">\r
<Filter>JUCE Modules\juce_core\time</Filter>\r
</ClCompile>\r
<ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_RuntimePermissions.h">\r
<Filter>JUCE Modules\juce_core\misc</Filter>\r
</ClInclude>\r
- <ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_StdFunctionCompat.h">\r
- <Filter>JUCE Modules\juce_core\misc</Filter>\r
- </ClInclude>\r
<ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_Uuid.h">\r
<Filter>JUCE Modules\juce_core\misc</Filter>\r
</ClInclude>\r
\r
#define JUCE_USE_DARK_SPLASH_SCREEN 1\r
\r
-#define JUCE_PROJUCER_VERSION 0x50405\r
+#define JUCE_PROJUCER_VERSION 0x50406\r
\r
//==============================================================================\r
#define JUCE_MODULE_AVAILABLE_juce_analytics 1\r
//==============================================================================\r
// juce_events flags:\r
\r
-#ifndef JUCE_EXECUTE_APP_SUSPEND_ON_IOS_BACKGROUND_TASK\r
- //#define JUCE_EXECUTE_APP_SUSPEND_ON_IOS_BACKGROUND_TASK 0\r
+#ifndef JUCE_EXECUTE_APP_SUSPEND_ON_BACKGROUND_TASK\r
+ //#define JUCE_EXECUTE_APP_SUSPEND_ON_BACKGROUND_TASK 0\r
#endif\r
\r
//==============================================================================\r
==============================================================================\r
*/\r
\r
-#include "../JuceLibraryCode/JuceHeader.h"\r
+#include <JuceHeader.h>\r
\r
//==============================================================================\r
class ConsoleLogger : public Logger\r
<?xml version="1.0" encoding="UTF-8"?>\r
\r
<JUCERPROJECT id="Z2Xzcp" name="UnitTestRunner" projectType="consoleapp" bundleIdentifier="com.roli.UnitTestRunner"\r
- jucerVersion="5.4.5" defines="JUCE_UNIT_TESTS=1" displaySplashScreen="0"\r
+ jucerVersion="5.4.6" defines="JUCE_UNIT_TESTS=1" displaySplashScreen="0"\r
reportAppUsage="0" companyName="ROLI Ltd." companyCopyright="ROLI Ltd.">\r
<MAINGROUP id="GZdWCU" name="UnitTestRunner">\r
<GROUP id="{22894462-E1A9-036F-ED94-B51A50C87552}" name="Source">\r
<ClCompile Include="..\..\..\..\modules\juce_core\misc\juce_RuntimePermissions.cpp">\r
<ExcludedFromBuild>true</ExcludedFromBuild>\r
</ClCompile>\r
- <ClCompile Include="..\..\..\..\modules\juce_core\misc\juce_StdFunctionCompat.cpp">\r
- <ExcludedFromBuild>true</ExcludedFromBuild>\r
- </ClCompile>\r
<ClCompile Include="..\..\..\..\modules\juce_core\misc\juce_Uuid.cpp">\r
<ExcludedFromBuild>true</ExcludedFromBuild>\r
</ClCompile>\r
<ClCompile Include="..\..\..\..\modules\juce_core\threads\juce_TimeSliceThread.cpp">\r
<ExcludedFromBuild>true</ExcludedFromBuild>\r
</ClCompile>\r
+ <ClCompile Include="..\..\..\..\modules\juce_core\threads\juce_WaitableEvent.cpp">\r
+ <ExcludedFromBuild>true</ExcludedFromBuild>\r
+ </ClCompile>\r
<ClCompile Include="..\..\..\..\modules\juce_core\time\juce_PerformanceCounter.cpp">\r
<ExcludedFromBuild>true</ExcludedFromBuild>\r
</ClCompile>\r
<ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_ConsoleApplication.h"/>\r
<ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_Result.h"/>\r
<ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_RuntimePermissions.h"/>\r
- <ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_StdFunctionCompat.h"/>\r
<ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_Uuid.h"/>\r
<ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_WindowsRegistry.h"/>\r
<ClInclude Include="..\..\..\..\modules\juce_core\native\juce_android_JNIHelpers.h"/>\r
<ClCompile Include="..\..\..\..\modules\juce_core\misc\juce_RuntimePermissions.cpp">\r
<Filter>JUCE Modules\juce_core\misc</Filter>\r
</ClCompile>\r
- <ClCompile Include="..\..\..\..\modules\juce_core\misc\juce_StdFunctionCompat.cpp">\r
- <Filter>JUCE Modules\juce_core\misc</Filter>\r
- </ClCompile>\r
<ClCompile Include="..\..\..\..\modules\juce_core\misc\juce_Uuid.cpp">\r
<Filter>JUCE Modules\juce_core\misc</Filter>\r
</ClCompile>\r
<ClCompile Include="..\..\..\..\modules\juce_core\threads\juce_TimeSliceThread.cpp">\r
<Filter>JUCE Modules\juce_core\threads</Filter>\r
</ClCompile>\r
+ <ClCompile Include="..\..\..\..\modules\juce_core\threads\juce_WaitableEvent.cpp">\r
+ <Filter>JUCE Modules\juce_core\threads</Filter>\r
+ </ClCompile>\r
<ClCompile Include="..\..\..\..\modules\juce_core\time\juce_PerformanceCounter.cpp">\r
<Filter>JUCE Modules\juce_core\time</Filter>\r
</ClCompile>\r
<ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_RuntimePermissions.h">\r
<Filter>JUCE Modules\juce_core\misc</Filter>\r
</ClInclude>\r
- <ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_StdFunctionCompat.h">\r
- <Filter>JUCE Modules\juce_core\misc</Filter>\r
- </ClInclude>\r
<ClInclude Include="..\..\..\..\modules\juce_core\misc\juce_Uuid.h">\r
<Filter>JUCE Modules\juce_core\misc</Filter>\r
</ClInclude>\r
\r
#define JUCE_USE_DARK_SPLASH_SCREEN 1\r
\r
-#define JUCE_PROJUCER_VERSION 0x50405\r
+#define JUCE_PROJUCER_VERSION 0x50406\r
\r
//==============================================================================\r
#define JUCE_MODULE_AVAILABLE_juce_audio_basics 1\r
//==============================================================================\r
// juce_events flags:\r
\r
-#ifndef JUCE_EXECUTE_APP_SUSPEND_ON_IOS_BACKGROUND_TASK\r
- //#define JUCE_EXECUTE_APP_SUSPEND_ON_IOS_BACKGROUND_TASK 0\r
+#ifndef JUCE_EXECUTE_APP_SUSPEND_ON_BACKGROUND_TASK\r
+ //#define JUCE_EXECUTE_APP_SUSPEND_ON_BACKGROUND_TASK 0\r
#endif\r
\r
//==============================================================================\r
<?xml version="1.0" encoding="UTF-8"?>\r
\r
<JUCERPROJECT id="IvabE4" name="WindowsDLL" projectType="library" juceLinkage="none"\r
- bundleIdentifier="com.roli.jucedll" jucerVersion="5.4.5" defines="JUCE_DLL_BUILD=1"\r
+ bundleIdentifier="com.roli.jucedll" jucerVersion="5.4.6" defines="JUCE_DLL_BUILD=1"\r
displaySplashScreen="0" reportAppUsage="0" companyName="ROLI Ltd."\r
companyCopyright="ROLI Ltd.">\r
<EXPORTFORMATS>\r
//==============================================================================\r
/**\r
Creating one of these automatically sends analytics events to the Analytics\r
- singeton when the corresponding button is clicked.\r
+ singleton when the corresponding button is clicked.\r
\r
The name and parameters of the analytics event will be populated from the\r
variables supplied here. If clicking changes the button's state then the\r
==============================================================================\r
*/\r
\r
+\r
/*******************************************************************************\r
The block below describes the properties of this module, and is read by\r
the Projucer to automatically generate project code that uses it.\r
\r
BEGIN_JUCE_MODULE_DECLARATION\r
\r
- ID: juce_analytics\r
- vendor: juce\r
- version: 5.4.5\r
- name: JUCE analytics classes\r
- description: Classes to collect analytics and send to destinations\r
- website: http://www.juce.com/juce\r
- license: GPL/Commercial\r
+ ID: juce_analytics\r
+ vendor: juce\r
+ version: 5.4.6\r
+ name: JUCE analytics classes\r
+ description: Classes to collect analytics and send to destinations\r
+ website: http://www.juce.com/juce\r
+ license: GPL/Commercial\r
\r
- dependencies: juce_gui_basics\r
+ dependencies: juce_gui_basics\r
\r
END_JUCE_MODULE_DECLARATION\r
\r
/**\r
Maintains an ongoing measurement of the proportion of time which is being\r
spent inside an audio callback.\r
+\r
+ @tags{Audio}\r
*/\r
class JUCE_API AudioProcessLoadMeasurer\r
{\r
myCallback->doTheCallback();\r
}\r
@endcode\r
+\r
+ @tags{Audio}\r
*/\r
struct JUCE_API ScopedTimer\r
{\r
/** Copies another buffer.\r
\r
This buffer will make its own copy of the other's data, unless the buffer was created\r
- using an external data buffer, in which case boths buffers will just point to the same\r
+ using an external data buffer, in which case both buffers will just point to the same\r
shared block of data.\r
*/\r
AudioBuffer (const AudioBuffer& other)\r
\r
void allocateData()\r
{\r
+ static_assert (std::alignment_of<Type>::value <= std::alignment_of<std::max_align_t>::value,\r
+ "AudioBuffer cannot hold types with alignment requirements larger than that guaranteed by malloc");\r
jassert (size >= 0);\r
+\r
auto channelListSize = (size_t) (numChannels + 1) * sizeof (Type*);\r
+ auto requiredSampleAlignment = std::alignment_of<Type>::value;\r
+ size_t alignmentOverflow = channelListSize % requiredSampleAlignment;\r
+\r
+ if (alignmentOverflow != 0)\r
+ channelListSize += requiredSampleAlignment - alignmentOverflow;\r
+\r
allocatedBytes = (size_t) numChannels * (size_t) size * sizeof (Type) + channelListSize + 32;\r
allocatedData.malloc (allocatedBytes);\r
channels = reinterpret_cast<Type**> (allocatedData.get());\r
==============================================================================\r
*/\r
\r
+\r
/*******************************************************************************\r
The block below describes the properties of this module, and is read by\r
the Projucer to automatically generate project code that uses it.\r
\r
BEGIN_JUCE_MODULE_DECLARATION\r
\r
- ID: juce_audio_basics\r
- vendor: juce\r
- version: 5.4.5\r
- name: JUCE audio and MIDI data classes\r
- description: Classes for audio buffer manipulation, midi message handling, synthesis, etc.\r
- website: http://www.juce.com/juce\r
- license: ISC\r
-\r
- dependencies: juce_core\r
- OSXFrameworks: Accelerate\r
- iOSFrameworks: Accelerate\r
+ ID: juce_audio_basics\r
+ vendor: juce\r
+ version: 5.4.6\r
+ name: JUCE audio and MIDI data classes\r
+ description: Classes for audio buffer manipulation, midi message handling, synthesis, etc.\r
+ website: http://www.juce.com/juce\r
+ license: ISC\r
+\r
+ dependencies: juce_core\r
+ OSXFrameworks: Accelerate\r
+ iOSFrameworks: Accelerate\r
\r
END_JUCE_MODULE_DECLARATION\r
\r
Represents a piano keyboard, keeping track of which keys are currently pressed.\r
\r
This object can parse a stream of midi events, using them to update its idea\r
- of which keys are pressed for each individiual midi channel.\r
+ of which keys are pressed for each individual midi channel.\r
\r
When keys go up or down, it can broadcast these events to listener objects.\r
\r
It will also trigger a synchronous callback to the listeners to tell them that the key has\r
gone up.\r
\r
- But if the note isn't acutally down for the given channel, this method will in fact do nothing.\r
+ But if the note isn't actually down for the given channel, this method will in fact do nothing.\r
*/\r
void noteOff (int midiChannel, int midiNoteNumber, float velocity);\r
\r
expectEquals (s.getIndexOfMatchingKeyUp (0), 2);\r
expectEquals (s.getIndexOfMatchingKeyUp (1), 3);\r
\r
- beginTest ("Time & indeces");\r
+ beginTest ("Time & indices");\r
expectEquals (s.getNextIndexAtTime (0.5), 1);\r
expectEquals (s.getNextIndexAtTime (2.5), 2);\r
expectEquals (s.getNextIndexAtTime (9.0), 4);\r
\r
@param use14BitValue If true (default), the value will have 14-bit precision\r
(two MIDI bytes). If false, instead the value will have\r
- 7-bit presision (a single MIDI byte).\r
+ 7-bit precision (a single MIDI byte).\r
*/\r
static MidiBuffer generate (int channel,\r
int parameterNumber,\r
/**\r
This class represents an instrument handling MPE.\r
\r
- It has an MPE zone layout and maintans a state of currently\r
+ It has an MPE zone layout and maintains a state of currently\r
active (playing) notes and the values of their dimensions of expression.\r
\r
You can trigger and modulate notes:\r
\r
/** Returns the sequence of MIDI messages that, if sent to an Expressive\r
MIDI device, will reset the whole MPE zone layout of the\r
- device to the laoyut passed in. This will first clear the current lower and upper\r
+ device to the layout passed in. This will first clear the current lower and upper\r
zones, then then set the zones contained in the passed-in zone layout, and set their\r
per-note and master pitchbend ranges to their current values.\r
*/\r
int numSamples) override;\r
\r
/** This will simply call renderNextBlock for each currently active\r
- voice and fill the buffer with the sum. (souble-precision version)\r
+ voice and fill the buffer with the sum. (double-precision version)\r
Override this method if you need to do more work to render your audio.\r
*/\r
void renderNextSubBlock (AudioBuffer<double>& outputAudio,\r
\r
int MPEChannelAssigner::findMidiChannelForNewNote (int noteNumber) noexcept\r
{\r
- if (numChannels == 1)\r
+ if (numChannels <= 1)\r
return firstChannel;\r
\r
for (auto ch = firstChannel; (isLegacy || zone->isLowerZone() ? ch <= lastChannel : ch >= lastChannel); ch += channelIncrement)\r
\r
An AudioSource has two states: prepared and unprepared.\r
\r
- The prepareToPlay() method is guaranteed to be called at least once on an 'unpreprared'\r
+ The prepareToPlay() method is guaranteed to be called at least once on an 'unprepared'\r
source to put it into a 'prepared' state before any calls will be made to getNextAudioBlock().\r
This callback allows the source to initialise any resources it might need when playing.\r
\r
To use it, call setSampleRate() with the current sample rate and give it some parameters\r
with setParameters() then call getNextSample() to get the envelope value to be applied\r
to each audio sample or applyEnvelopeToBuffer() to apply the envelope to a whole buffer.\r
+\r
+ @tags{Audio}\r
*/\r
class ADSR\r
{\r
}\r
\r
//==============================================================================\r
- /** Holds the parameters being used by an ADSR object. */\r
+ /**\r
+ Holds the parameters being used by an ADSR object.\r
+\r
+ @tags{Audio}\r
+ */\r
struct Parameters\r
{\r
/** Attack time in seconds. */\r
{\r
envelopeVal = 0.0f;\r
currentState = State::idle;\r
-\r
- if (resetReleaseRate)\r
- {\r
- releaseRate = static_cast<float> (sustainLevel / (currentParameters.release * sr));\r
- resetReleaseRate = false;\r
- }\r
}\r
\r
/** Starts the attack phase of the envelope. */\r
{\r
if (currentState != State::idle)\r
{\r
- if (releaseRate > 0.0f)\r
+ if (currentParameters.release > 0.0f)\r
{\r
- if (currentState != State::sustain)\r
- {\r
- releaseRate = static_cast<float> (envelopeVal / (currentParameters.release * sr));\r
- resetReleaseRate = true;\r
- }\r
-\r
+ releaseRate = static_cast<float> (envelopeVal / (currentParameters.release * sr));\r
currentState = State::release;\r
}\r
else\r
\r
attackRate = (parameters.attack > 0.0f ? static_cast<float> (1.0f / (parameters.attack * sr)) : -1.0f);\r
decayRate = (parameters.decay > 0.0f ? static_cast<float> ((1.0f - sustainLevel) / (parameters.decay * sr)) : -1.0f);\r
- releaseRate = (parameters.release > 0.0f ? static_cast<float> (sustainLevel / (parameters.release * sr)) : -1.0f);\r
}\r
\r
void checkCurrentState()\r
\r
double sr = 0.0;\r
float envelopeVal = 0.0f, sustainLevel = 0.0f, attackRate = 0.0f, decayRate = 0.0f, releaseRate = 0.0f;\r
- bool resetReleaseRate = false;\r
};\r
\r
} // namespace juce\r
*/\r
namespace ValueSmoothingTypes\r
{\r
- /** Used to indicate a linear smoothing between values. */\r
+ /**\r
+ Used to indicate a linear smoothing between values.\r
+\r
+ @tags{Audio}\r
+ */\r
struct Linear {};\r
\r
- /** Used to indicate a smoothing between multiplicative values. */\r
+ /**\r
+ Used to indicate a smoothing between multiplicative values.\r
+\r
+ @tags{Audio}\r
+ */\r
struct Multiplicative {};\r
}\r
\r
createAudioDeviceTypes (types);\r
\r
for (auto* t : types)\r
- addAudioDeviceType (t);\r
+ addAudioDeviceType (std::unique_ptr<AudioIODeviceType> (t));\r
\r
types.clear (false);\r
\r
addIfNotNull (list, AudioIODeviceType::createAudioIODeviceType_ASIO());\r
addIfNotNull (list, AudioIODeviceType::createAudioIODeviceType_CoreAudio());\r
addIfNotNull (list, AudioIODeviceType::createAudioIODeviceType_iOSAudio());\r
+ addIfNotNull (list, AudioIODeviceType::createAudioIODeviceType_Bela());\r
addIfNotNull (list, AudioIODeviceType::createAudioIODeviceType_ALSA());\r
addIfNotNull (list, AudioIODeviceType::createAudioIODeviceType_JACK());\r
- addIfNotNull (list, AudioIODeviceType::createAudioIODeviceType_Bela());\r
addIfNotNull (list, AudioIODeviceType::createAudioIODeviceType_Oboe());\r
addIfNotNull (list, AudioIODeviceType::createAudioIODeviceType_OpenSLES());\r
addIfNotNull (list, AudioIODeviceType::createAudioIODeviceType_Android());\r
}\r
\r
-void AudioDeviceManager::addAudioDeviceType (AudioIODeviceType* newDeviceType)\r
+void AudioDeviceManager::addAudioDeviceType (std::unique_ptr<AudioIODeviceType> newDeviceType)\r
{\r
if (newDeviceType != nullptr)\r
{\r
jassert (lastDeviceTypeConfigs.size() == availableDeviceTypes.size());\r
- availableDeviceTypes.add (newDeviceType);\r
+\r
+ availableDeviceTypes.add (newDeviceType.release());\r
lastDeviceTypeConfigs.add (new AudioDeviceSetup());\r
\r
- newDeviceType->addListener (callbackHandler.get());\r
+ availableDeviceTypes.getLast()->addListener (callbackHandler.get());\r
+ }\r
+}\r
+\r
+void AudioDeviceManager::removeAudioDeviceType (AudioIODeviceType* deviceTypeToRemove)\r
+{\r
+ if (deviceTypeToRemove != nullptr)\r
+ {\r
+ jassert (lastDeviceTypeConfigs.size() == availableDeviceTypes.size());\r
+\r
+ auto index = availableDeviceTypes.indexOf (deviceTypeToRemove);\r
+\r
+ if (auto removed = std::unique_ptr<AudioIODeviceType> (availableDeviceTypes.removeAndReturn (index)))\r
+ {\r
+ removed->removeListener (callbackHandler.get());\r
+ lastDeviceTypeConfigs.remove (index, true);\r
+ }\r
}\r
}\r
\r
*/\r
virtual void createAudioDeviceTypes (OwnedArray<AudioIODeviceType>& types);\r
\r
- /** Adds a new device type to the list of types.\r
- The manager will take ownership of the object that is passed-in.\r
- */\r
- void addAudioDeviceType (AudioIODeviceType* newDeviceType);\r
+ /** Adds a new device type to the list of types. */\r
+ void addAudioDeviceType (std::unique_ptr<AudioIODeviceType> newDeviceType);\r
+\r
+ /** Removes a previously added device type from the manager. */\r
+ void removeAudioDeviceType (AudioIODeviceType* deviceTypeToRemove);\r
\r
//==============================================================================\r
/** Plays a beep through the current audio device.\r
==============================================================================\r
*/\r
\r
+\r
/*******************************************************************************\r
The block below describes the properties of this module, and is read by\r
the Projucer to automatically generate project code that uses it.\r
\r
BEGIN_JUCE_MODULE_DECLARATION\r
\r
- ID: juce_audio_devices\r
- vendor: juce\r
- version: 5.4.5\r
- name: JUCE audio and MIDI I/O device classes\r
- description: Classes to play and record from audio and MIDI I/O devices\r
- website: http://www.juce.com/juce\r
- license: ISC\r
+ ID: juce_audio_devices\r
+ vendor: juce\r
+ version: 5.4.6\r
+ name: JUCE audio and MIDI I/O device classes\r
+ description: Classes to play and record from audio and MIDI I/O devices\r
+ website: http://www.juce.com/juce\r
+ license: ISC\r
\r
- dependencies: juce_audio_basics, juce_events\r
- OSXFrameworks: CoreAudio CoreMIDI AudioToolbox\r
- iOSFrameworks: CoreAudio CoreMIDI AudioToolbox AVFoundation\r
- linuxPackages: alsa\r
- mingwLibs: winmm\r
+ dependencies: juce_audio_basics, juce_events\r
+ OSXFrameworks: CoreAudio CoreMIDI AudioToolbox\r
+ iOSFrameworks: CoreAudio CoreMIDI AudioToolbox AVFoundation\r
+ linuxPackages: alsa\r
+ mingwLibs: winmm\r
\r
END_JUCE_MODULE_DECLARATION\r
\r
Enables the use of the Windows Runtime API for MIDI, allowing connections\r
to Bluetooth Low Energy devices on Windows 10 version 1809 (October 2018\r
Update) and later. If you enable this flag then older, unsupported,\r
- versions of Windows will automatically fall back to using the regualar\r
+ versions of Windows will automatically fall back to using the regular\r
Win32 MIDI API.\r
\r
You will need version 10.0.14393.0 of the Windows Standalone SDK to compile\r
getDefaultDevice() methods of MidiInput and MidiOutput or by calling getDeviceInfo()\r
on an instance of these classes. Devices can be opened by passing the identifier to\r
the openDevice() method.\r
+\r
+ @tags{Audio}\r
*/\r
struct MidiDeviceInfo\r
{\r
//==============================================================================\r
void MidiMessageCollector::reset (const double newSampleRate)\r
{\r
+ const ScopedLock sl (midiCallbackLock);\r
+\r
jassert (newSampleRate > 0);\r
\r
- const ScopedLock sl (midiCallbackLock);\r
#if JUCE_DEBUG\r
hasCalledReset = true;\r
#endif\r
\r
void MidiMessageCollector::addMessageToQueue (const MidiMessage& message)\r
{\r
+ const ScopedLock sl (midiCallbackLock);\r
+\r
#if JUCE_DEBUG\r
jassert (hasCalledReset); // you need to call reset() to set the correct sample rate before using this object\r
#endif\r
// for details of what the number should be.\r
jassert (message.getTimeStamp() != 0);\r
\r
- const ScopedLock sl (midiCallbackLock);\r
-\r
auto sampleNumber = (int) ((message.getTimeStamp() - 0.001 * lastCallbackTime) * sampleRate);\r
\r
incomingMessages.addEvent (message, sampleNumber);\r
void MidiMessageCollector::removeNextBlockOfMessages (MidiBuffer& destBuffer,\r
const int numSamples)\r
{\r
+ const ScopedLock sl (midiCallbackLock);\r
+\r
#if JUCE_DEBUG\r
jassert (hasCalledReset); // you need to call reset() to set the correct sample rate before using this object\r
#endif\r
auto timeNow = Time::getMillisecondCounterHiRes();\r
auto msElapsed = timeNow - lastCallbackTime;\r
\r
- const ScopedLock sl (midiCallbackLock);\r
lastCallbackTime = timeNow;\r
\r
if (! incomingMessages.isEmpty())\r
// only the player or the recorder should enter this section at any time\r
if (guard.compareAndSetBool (1, 0))\r
{\r
- // are there enough buffers avaialable to process some audio\r
+ // are there enough buffers available to process some audio\r
if ((inputChannels == 0 || recorder->isBufferAvailable()) && (outputChannels == 0 || player->isBufferAvailable()))\r
{\r
T* recorderBuffer = (inputChannels > 0 ? recorder->getNextBuffer() : nullptr);\r
22050.0, 24000.0, 32000.0, 44100.0, 48000.0 };\r
Array<double> retval (rates, numElementsInArray (rates));\r
\r
- // make sure the native sample rate is pafrt of the list\r
+ // make sure the native sample rate is part of the list\r
double native = getNativeSampleRate();\r
\r
if (native != 0.0 && ! retval.contains (native))\r
snd_device_name_free_hint (hints);\r
}\r
\r
- // sometimes the "default" device is not listed, but it is nice to see it explicitely in the list\r
+ // sometimes the "default" device is not listed, but it is nice to see it explicitly in the list\r
if (! outputIds.contains ("default"))\r
testDevice ("default", "Default ALSA Output", "Default ALSA Input");\r
\r
BigInteger getActiveInputChannels() const override { BigInteger b; b.setRange (0, actualNumberOfInputs, true); return b; }\r
int getOutputLatencyInSamples() override { /* TODO */ return 0; }\r
int getInputLatencyInSamples() override { /* TODO */ return 0; }\r
- int getXRunCount() const noexcept { return underruns; }\r
+ int getXRunCount() const noexcept override { return underruns; }\r
\r
//==============================================================================\r
static const char* const belaTypeName;\r
\r
//==============================================================================\r
#ifndef JUCE_JACK_CLIENT_NAME\r
- #define JUCE_JACK_CLIENT_NAME "JUCEJack"\r
+ #ifdef JucePlugin_Name\r
+ #define JUCE_JACK_CLIENT_NAME JucePlugin_Name\r
+ #else\r
+ #define JUCE_JACK_CLIENT_NAME "JUCEJack"\r
+ #endif\r
#endif\r
\r
struct JackPortIterator\r
\r
#ifdef __clang__\r
#pragma clang diagnostic push\r
- #pragma clang diagnostic ignored "-Wnonnull" // aovid some spurious 10.11 SDK warnings\r
+ #pragma clang diagnostic ignored "-Wnonnull" // avoid some spurious 10.11 SDK warnings\r
#endif\r
\r
//==============================================================================\r
\r
if (CHECK_ERROR (MIDIObjectSetIntegerProperty (endpoint, kMIDIPropertyUniqueID, (SInt32) deviceIdentifier)))\r
{\r
- mpc->portAndEndpoint = std::make_unique<MidiPortAndEndpoint> (0, endpoint);\r
+ mpc->portAndEndpoint = std::make_unique<MidiPortAndEndpoint> ((UInt32) 0, endpoint);\r
\r
std::unique_ptr<MidiInput> midiInput (new MidiInput (deviceName, String (deviceIdentifier)));\r
\r
\r
if (CHECK_ERROR (err))\r
{\r
- auto deviceIdentifier = createUniqueIDForMidiPort (deviceName, true);\r
+ auto deviceIdentifier = createUniqueIDForMidiPort (deviceName, false);\r
\r
if (CHECK_ERROR (MIDIObjectSetIntegerProperty (endpoint, kMIDIPropertyUniqueID, (SInt32) deviceIdentifier)))\r
{\r
{\r
message = "ASIO: " + message;\r
DBG (message);\r
- Logger::writeToLog (message);\r
+\r
+ if (Logger::getCurrentLogger() != nullptr)\r
+ Logger::writeToLog (message);\r
}\r
\r
static void logError (const String& context, long error)\r
\r
close();\r
JUCE_ASIO_LOG ("closed");\r
- removeCurrentDriver();\r
+\r
+ if (! removeCurrentDriver())\r
+ JUCE_ASIO_LOG ("** Driver crashed while being closed");\r
}\r
\r
void updateSampleRates()\r
if (needToReset)\r
{\r
JUCE_ASIO_LOG (" Resetting");\r
- removeCurrentDriver();\r
+\r
+ if (! removeCurrentDriver())\r
+ JUCE_ASIO_LOG ("** Driver crashed while being closed");\r
\r
loadDriver();\r
String initError = initDriver();\r
BigInteger getActiveOutputChannels() const override { return currentChansOut; }\r
BigInteger getActiveInputChannels() const override { return currentChansIn; }\r
\r
- int getOutputLatencyInSamples() override { return outputLatency + currentBlockSizeSamples / 4; }\r
- int getInputLatencyInSamples() override { return inputLatency + currentBlockSizeSamples / 4; }\r
+ int getOutputLatencyInSamples() override { return outputLatency; }\r
+ int getInputLatencyInSamples() override { return inputLatency; }\r
\r
void start (AudioIODeviceCallback* callback) override\r
{\r
}\r
}\r
\r
- static bool shouldReleaseObject (const String& driverName)\r
+ bool removeCurrentDriver()\r
{\r
- return driverName != "Yamaha Steinberg USB ASIO";\r
- }\r
+ bool releasedOK = true;\r
\r
- void removeCurrentDriver()\r
- {\r
if (asioObject != nullptr)\r
{\r
- char buffer[512] = {};\r
- asioObject->getDriverName (buffer);\r
-\r
- if (shouldReleaseObject (buffer))\r
+ #if ! JUCE_MINGW\r
+ __try\r
+ #endif\r
+ {\r
asioObject->Release();\r
+ }\r
+ #if ! JUCE_MINGW\r
+ __except (EXCEPTION_EXECUTE_HANDLER) { releasedOK = false; }\r
+ #endif\r
\r
asioObject = nullptr;\r
}\r
+\r
+ return releasedOK;\r
}\r
\r
bool loadDriver()\r
{\r
- removeCurrentDriver();\r
+ if (! removeCurrentDriver())\r
+ JUCE_ASIO_LOG ("** Driver crashed while being closed");\r
\r
bool crashed = false;\r
bool ok = tryCreatingDriver (crashed);\r
{\r
JUCE_ASIO_LOG_ERROR (error, err);\r
disposeBuffers();\r
- removeCurrentDriver();\r
+\r
+ if (! removeCurrentDriver())\r
+ JUCE_ASIO_LOG ("** Driver crashed while being closed");\r
}\r
else\r
{\r
//==============================================================================\r
WinRTMidiService()\r
{\r
- if (! WinRTWrapper::getInstance()->isInitialised())\r
+ auto* wrtWrapper = WinRTWrapper::getInstance();\r
+\r
+ if (! wrtWrapper->isInitialised())\r
throw std::runtime_error ("Failed to initialise the WinRT wrapper");\r
\r
- midiInFactory = WinRTWrapper::getInstance()->getWRLFactory<IMidiInPortStatics> (&RuntimeClass_Windows_Devices_Midi_MidiInPort[0]);\r
+ midiInFactory = wrtWrapper->getWRLFactory<IMidiInPortStatics> (&RuntimeClass_Windows_Devices_Midi_MidiInPort[0]);\r
\r
if (midiInFactory == nullptr)\r
throw std::runtime_error ("Failed to create midi in factory");\r
\r
- midiOutFactory = WinRTWrapper::getInstance()->getWRLFactory<IMidiOutPortStatics> (&RuntimeClass_Windows_Devices_Midi_MidiOutPort[0]);\r
+ midiOutFactory = wrtWrapper->getWRLFactory<IMidiOutPortStatics> (&RuntimeClass_Windows_Devices_Midi_MidiOutPort[0]);\r
\r
if (midiOutFactory == nullptr)\r
throw std::runtime_error ("Failed to create midi out factory");\r
\r
bool attach (HSTRING deviceSelector, DeviceInformationKind infoKind)\r
{\r
- auto deviceInfoFactory = WinRTWrapper::getInstance()->getWRLFactory<IDeviceInformationStatics2> (&RuntimeClass_Windows_Devices_Enumeration_DeviceInformation[0]);\r
+ auto* wrtWrapper = WinRTWrapper::getInstanceWithoutCreating();\r
+\r
+ if (wrtWrapper == nullptr)\r
+ {\r
+ JUCE_WINRT_MIDI_LOG ("Failed to get the WinRTWrapper singleton!");\r
+ return false;\r
+ }\r
+\r
+ auto deviceInfoFactory = wrtWrapper->getWRLFactory<IDeviceInformationStatics2> (&RuntimeClass_Windows_Devices_Enumeration_DeviceInformation[0]);\r
\r
if (deviceInfoFactory == nullptr)\r
return false;\r
\r
// A quick way of getting an IVector<HSTRING>...\r
- auto requestedProperties = []\r
+ auto requestedProperties = [wrtWrapper]\r
{\r
- auto devicePicker = WinRTWrapper::getInstance()->activateInstance<IDevicePicker> (&RuntimeClass_Windows_Devices_Enumeration_DevicePicker[0],\r
- __uuidof (IDevicePicker));\r
+ auto devicePicker = wrtWrapper->activateInstance<IDevicePicker> (&RuntimeClass_Windows_Devices_Enumeration_DevicePicker[0],\r
+ __uuidof (IDevicePicker));\r
jassert (devicePicker != nullptr);\r
\r
IVector<HSTRING>* result;\r
return result;\r
}();\r
\r
- StringArray propertyKeys = { "System.Devices.ContainerId",\r
- "System.Devices.Aep.ContainerId",\r
- "System.Devices.Aep.IsConnected" };\r
+ StringArray propertyKeys ("System.Devices.ContainerId",\r
+ "System.Devices.Aep.ContainerId",\r
+ "System.Devices.Aep.IsConnected");\r
\r
for (auto& key : propertyKeys)\r
{\r
Callback<ITypedEventHandler<DeviceWatcher*, DeviceInformationUpdate*>> (\r
[handlerPtr](IDeviceWatcher*, IDeviceInformationUpdate* infoUpdate) { return handlerPtr->updateDevice (infoUpdate); }\r
).Get(),\r
- &deviceRemovedToken);\r
+ &deviceUpdatedToken);\r
\r
watcher->Start();\r
}\r
return S_OK;\r
}\r
\r
- auto deviceID = WinRTWrapper::getInstance()->hStringToString (deviceIDHst);\r
+ auto* wrtWrapper = WinRTWrapper::getInstanceWithoutCreating();\r
+\r
+ if (wrtWrapper == nullptr)\r
+ {\r
+ JUCE_WINRT_MIDI_LOG ("Failed to get the WinRTWrapper singleton!");\r
+ return false;\r
+ }\r
+\r
+ auto deviceID = wrtWrapper->hStringToString (deviceIDHst);\r
JUCE_WINRT_MIDI_LOG ("Detected paired BLE device: " << deviceID);\r
\r
if (auto* containerIDValue = getValueFromDeviceInfo ("System.Devices.Aep.ContainerId", addedDeviceInfo))\r
return S_OK;\r
}\r
\r
- auto removedDeviceId = WinRTWrapper::getInstance()->hStringToString (removedDeviceIdHstr);\r
+ auto* wrtWrapper = WinRTWrapper::getInstanceWithoutCreating();\r
+\r
+ if (wrtWrapper == nullptr)\r
+ {\r
+ JUCE_WINRT_MIDI_LOG ("Failed to get the WinRTWrapper singleton!");\r
+ return false;\r
+ }\r
+\r
+ auto removedDeviceId = wrtWrapper->hStringToString (removedDeviceIdHstr);\r
\r
JUCE_WINRT_MIDI_LOG ("Removing BLE device: " << removedDeviceId);\r
\r
return S_OK;\r
}\r
\r
- auto updatedDeviceId = WinRTWrapper::getInstance()->hStringToString (updatedDeviceIdHstr);\r
+ auto* wrtWrapper = WinRTWrapper::getInstanceWithoutCreating();\r
+\r
+ if (wrtWrapper == nullptr)\r
+ {\r
+ JUCE_WINRT_MIDI_LOG ("Failed to get the WinRTWrapper singleton!");\r
+ return false;\r
+ }\r
+\r
+ auto updatedDeviceId = wrtWrapper->hStringToString (updatedDeviceIdHstr);\r
\r
JUCE_WINRT_MIDI_LOG ("Updating BLE device: " << updatedDeviceId);\r
\r
return S_OK;\r
}\r
\r
- info.deviceID = WinRTWrapper::getInstance()->hStringToString (deviceID);\r
+ auto* wrtWrapper = WinRTWrapper::getInstanceWithoutCreating();\r
+\r
+ if (wrtWrapper == nullptr)\r
+ {\r
+ JUCE_WINRT_MIDI_LOG ("Failed to get the WinRTWrapper singleton!");\r
+ return false;\r
+ }\r
+\r
+ info.deviceID = wrtWrapper->hStringToString (deviceID);\r
\r
JUCE_WINRT_MIDI_LOG ("Detected MIDI device: " << info.deviceID);\r
\r
return S_OK;\r
}\r
\r
- info.name = WinRTWrapper::getInstance()->hStringToString (name);\r
+ info.name = wrtWrapper->hStringToString (name);\r
\r
boolean isDefault = false;\r
hr = addedDeviceInfo->get_IsDefault (&isDefault);\r
return S_OK;\r
}\r
\r
- auto removedDeviceId = WinRTWrapper::getInstance()->hStringToString (removedDeviceIdHstr);\r
+ auto* wrtWrapper = WinRTWrapper::getInstanceWithoutCreating();\r
+\r
+ if (wrtWrapper == nullptr)\r
+ {\r
+ JUCE_WINRT_MIDI_LOG ("Failed to get the WinRTWrapper singleton!");\r
+ return false;\r
+ }\r
+\r
+ auto removedDeviceId = wrtWrapper->hStringToString (removedDeviceIdHstr);\r
\r
JUCE_WINRT_MIDI_LOG ("Removing MIDI device: " << removedDeviceId);\r
\r
}\r
).Get());\r
\r
- // We need to use a timout here, rather than waiting indefinitely, as the\r
- // WinRT API can occaisonally hang!\r
+ // We need to use a timeout here, rather than waiting indefinitely, as the\r
+ // WinRT API can occasionally hang!\r
portOpened.wait (2000);\r
}\r
\r
if (midiPort == nullptr)\r
throw std::runtime_error ("Timed out waiting for midi output port creation");\r
\r
- auto bufferFactory = WinRTWrapper::getInstance()->getWRLFactory<IBufferFactory> (&RuntimeClass_Windows_Storage_Streams_Buffer[0]);\r
+ auto* wrtWrapper = WinRTWrapper::getInstanceWithoutCreating();\r
+\r
+ if (wrtWrapper == nullptr)\r
+ throw std::runtime_error ("Failed to get the WinRTWrapper singleton!");\r
+\r
+ auto bufferFactory = wrtWrapper->getWRLFactory<IBufferFactory> (&RuntimeClass_Windows_Storage_Streams_Buffer[0]);\r
\r
if (bufferFactory == nullptr)\r
throw std::runtime_error ("Failed to create output buffer factory");\r
\r
//==============================================================================\r
//==============================================================================\r
-extern RTL_OSVERSIONINFOW getWindowsVersionInfo();\r
+#if ! JUCE_MINGW\r
+ extern RTL_OSVERSIONINFOW getWindowsVersionInfo();\r
+#endif\r
\r
struct MidiService : public DeletedAtShutdown\r
{\r
MidiService()\r
{\r
- #if JUCE_USE_WINRT_MIDI\r
+ #if JUCE_USE_WINRT_MIDI && ! JUCE_MINGW\r
#if ! JUCE_FORCE_WINRT_MIDI\r
auto windowsVersionInfo = getWindowsVersionInfo();\r
if (windowsVersionInfo.dwMajorVersion >= 10 && windowsVersionInfo.dwBuildNumber >= 17763)\r
float* outputChans[128];\r
const float* inputChans[128];\r
AudioBuffer<float> tempBuffer;\r
- float lastGain = 1.0f, gain = 1.0f;\r
+ float lastGain = 1.0f;\r
+ std::atomic<float> gain { 1.0f };\r
\r
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioSourcePlayer)\r
};\r
\r
auto status = AudioFileOpenWithCallbacks (this,\r
&readCallback,\r
- nullptr, // write needs to be null to avoid permisisions errors\r
+ nullptr, // write needs to be null to avoid permissions errors\r
&getSizeCallback,\r
- nullptr, // setSize needs to be null to avoid permisisions errors\r
+ nullptr, // setSize needs to be null to avoid permissions errors\r
0, // AudioFileTypeID inFileTypeHint\r
&audioFileID);\r
if (status == noErr)\r
: UnitTest ("Core Audio Layout <-> JUCE channel layout conversion", UnitTestCategories::audio)\r
{}\r
\r
- // some ambisonic tags which are not explicitely defined\r
+ // some ambisonic tags which are not explicitly defined\r
enum\r
{\r
kAudioChannelLayoutTag_HOA_ACN_SN3D_0Order = (190U<<16) | 1,\r
}\r
else if (chunkType == chunkName ("data"))\r
{\r
- if (! isRF64) // data size is expected to be -1, actual data size is in ds64 chunk\r
+ if (isRF64)\r
+ {\r
+ if (dataLength > 0)\r
+ chunkEnd = input->getPosition() + dataLength + (dataLength & 1);\r
+ }\r
+ else\r
+ {\r
dataLength = length;\r
+ }\r
\r
dataChunkStart = input->getPosition();\r
lengthInSamples = (bytesPerFrame > 0) ? (dataLength / bytesPerFrame) : 0;\r
{\r
// failed to write to disk, so let's try writing the header.\r
// If it's just run out of disk space, then if it does manage\r
- // to write the header, we'll still have a useable file..\r
+ // to write the header, we'll still have a usable file..\r
writeHeader();\r
writeFailed = true;\r
return false;\r
if (hasJumped)\r
bufferedRange.setStart ((int64) ((sampleTime * (int64) sampleRate) / 10000000));\r
else\r
- bufferedRange.setStart (bufferedRange.getEnd()); // (because the positions returned often aren't continguous)\r
+ bufferedRange.setStart (bufferedRange.getEnd()); // (because the positions returned often aren't contiguous)\r
\r
bufferedRange.setLength ((int64) (dataLength / stride));\r
\r
to try to open a different format, etc\r
@param sampleRateToUse the sample rate for the file, which must be one of the ones\r
returned by getPossibleSampleRates()\r
- @param numberOfChannels the number of channels - this must be either 1 or 2, and\r
- the choice will depend on the results of canDoMono() and\r
- canDoStereo()\r
+ @param numberOfChannels the number of channels\r
@param bitsPerSample the bits per sample to use - this must be one of the values\r
returned by getPossibleBitDepths()\r
@param metadataValues a set of metadata values that the writer should try to write\r
==============================================================================\r
*/\r
\r
+\r
/*******************************************************************************\r
The block below describes the properties of this module, and is read by\r
the Projucer to automatically generate project code that uses it.\r
\r
BEGIN_JUCE_MODULE_DECLARATION\r
\r
- ID: juce_audio_formats\r
- vendor: juce\r
- version: 5.4.5\r
- name: JUCE audio file format codecs\r
- description: Classes for reading and writing various audio file formats.\r
- website: http://www.juce.com/juce\r
- license: GPL/Commercial\r
-\r
- dependencies: juce_audio_basics\r
- OSXFrameworks: CoreAudio CoreMIDI QuartzCore AudioToolbox\r
- iOSFrameworks: AudioToolbox QuartzCore\r
+ ID: juce_audio_formats\r
+ vendor: juce\r
+ version: 5.4.6\r
+ name: JUCE audio file format codecs\r
+ description: Classes for reading and writing various audio file formats.\r
+ website: http://www.juce.com/juce\r
+ license: GPL/Commercial\r
+\r
+ dependencies: juce_audio_basics\r
+ OSXFrameworks: CoreAudio CoreMIDI QuartzCore AudioToolbox\r
+ iOSFrameworks: AudioToolbox QuartzCore\r
\r
END_JUCE_MODULE_DECLARATION\r
\r
info.timeInSeconds = info.timeInSamples / sampleRate;\r
\r
int64_t ticks = 0;\r
- check (transport.GetCurrentTickPosition (&ticks));\r
+\r
+ if (info.isPlaying)\r
+ check (transport.GetCustomTickPosition (&ticks, info.timeInSamples));\r
+ else\r
+ check (transport.GetCurrentTickPosition (&ticks));\r
+\r
info.ppqPosition = ticks / 960000.0;\r
\r
info.isLooping = false;\r
\r
if (isInAudioSuite())\r
{\r
- // AudioSuite doesnt support multiple output buses\r
+ // AudioSuite doesn't support multiple output buses\r
for (int i = 1; i < newLayout.outputBuses.size(); ++i)\r
newLayout.outputBuses.getReference (i) = AudioChannelSet::disabled();\r
\r
if (LegacyAudioParameter::getParamID (aaxMeters[idx], false) == paramID)\r
break;\r
\r
- // you sepecified a parameter id in your curve but the parameter does not have the meter\r
+ // you specified a parameter id in your curve but the parameter does not have the meter\r
// category\r
jassert (idx < aaxMeters.size());\r
return 'Metr' + static_cast<AAX_CTypeID> (idx);\r
{\r
DialogWindow::LaunchOptions o;\r
\r
- int minNumInputs = std::numeric_limits<int>::max(), maxNumInputs = 0,\r
- minNumOutputs = std::numeric_limits<int>::max(), maxNumOutputs = 0;\r
-\r
- auto updateMinAndMax = [] (int newValue, int& minValue, int& maxValue)\r
- {\r
- minValue = jmin (minValue, newValue);\r
- maxValue = jmax (maxValue, newValue);\r
- };\r
+ int maxNumInputs = 0, maxNumOutputs = 0;\r
\r
if (channelConfiguration.size() > 0)\r
{\r
- auto defaultConfig = channelConfiguration.getReference (0);\r
- updateMinAndMax ((int) defaultConfig.numIns, minNumInputs, maxNumInputs);\r
- updateMinAndMax ((int) defaultConfig.numOuts, minNumOutputs, maxNumOutputs);\r
+ auto& defaultConfig = channelConfiguration.getReference (0);\r
+\r
+ maxNumInputs = jmax (0, (int) defaultConfig.numIns);\r
+ maxNumOutputs = jmax (0, (int) defaultConfig.numOuts);\r
}\r
\r
if (auto* bus = processor->getBus (true, 0))\r
- updateMinAndMax (bus->getDefaultLayout().size(), minNumInputs, maxNumInputs);\r
+ maxNumInputs = jmax (0, bus->getDefaultLayout().size());\r
\r
if (auto* bus = processor->getBus (false, 0))\r
- updateMinAndMax (bus->getDefaultLayout().size(), minNumOutputs, maxNumOutputs);\r
-\r
- minNumInputs = jmin (minNumInputs, maxNumInputs);\r
- minNumOutputs = jmin (minNumOutputs, maxNumOutputs);\r
+ maxNumOutputs = jmax (0, bus->getDefaultLayout().size());\r
\r
- o.content.setOwned (new SettingsComponent (*this, deviceManager,\r
- minNumInputs,\r
- maxNumInputs,\r
- minNumOutputs,\r
- maxNumOutputs));\r
+ o.content.setOwned (new SettingsComponent (*this, deviceManager, maxNumInputs, maxNumOutputs));\r
o.content->setSize (500, 550);\r
\r
o.dialogTitle = TRANS("Audio/MIDI Settings");\r
public:\r
SettingsComponent (StandalonePluginHolder& pluginHolder,\r
AudioDeviceManager& deviceManagerToUse,\r
- int minAudioInputChannels,\r
int maxAudioInputChannels,\r
- int minAudioOutputChannels,\r
int maxAudioOutputChannels)\r
: owner (pluginHolder),\r
deviceSelector (deviceManagerToUse,\r
- minAudioInputChannels, maxAudioInputChannels,\r
- minAudioOutputChannels, maxAudioOutputChannels,\r
+ 0, maxAudioInputChannels,\r
+ 0, maxAudioOutputChannels,\r
true,\r
(pluginHolder.processor.get() != nullptr && pluginHolder.processor->producesMidi()),\r
true, false),\r
\r
#if JucePlugin_VersionCode < 0x010000 // Major < 0\r
\r
- #if (JucePlugin_VersionCode & 0x00FF00) > (9 * 0x100) // check if Minor number exceeeds 9\r
+ #if (JucePlugin_VersionCode & 0x00FF00) > (9 * 0x100) // check if Minor number exceeds 9\r
JUCE_COMPILER_WARNING ("When version has 'major' = 0, VST2 has trouble displaying 'minor' exceeding 9")\r
#endif\r
\r
- #if (JucePlugin_VersionCode & 0xFF) > 9 // check if Bugfix number exceeeds 9\r
+ #if (JucePlugin_VersionCode & 0xFF) > 9 // check if Bugfix number exceeds 9\r
JUCE_COMPILER_WARNING ("When version has 'major' = 0, VST2 has trouble displaying 'bugfix' exceeding 9")\r
#endif\r
\r
#elif JucePlugin_VersionCode >= 0x650000 // Major >= 101\r
\r
- #if (JucePlugin_VersionCode & 0x00FF00) > (99 * 0x100) // check if Minor number exceeeds 99\r
+ #if (JucePlugin_VersionCode & 0x00FF00) > (99 * 0x100) // check if Minor number exceeds 99\r
JUCE_COMPILER_WARNING ("When version has 'major' > 100, VST2 has trouble displaying 'minor' exceeding 99")\r
#endif\r
\r
- #if (JucePlugin_VersionCode & 0xFF) > 99 // check if Bugfix number exceeeds 99\r
+ #if (JucePlugin_VersionCode & 0xFF) > 99 // check if Bugfix number exceeds 99\r
JUCE_COMPILER_WARNING ("When version has 'major' > 100, VST2 has trouble displaying 'bugfix' exceeding 99")\r
#endif\r
\r
// The event loop needs to be run between closing the window and deleting the plugin,\r
// presumably to let the cocoa objects get tidied up. Leaving out this line causes crashes\r
// in Live when you delete the plugin with its window open.\r
- // (Doing it this way rather than using a single longer timout means that we can guarantee\r
+ // (Doing it this way rather than using a single longer timeout means that we can guarantee\r
// how many messages will be dispatched, which seems to be vital in Reaper)\r
if (needToRunMessageLoop)\r
for (int i = 20; --i >= 0;)\r
{\r
Param (JuceVST3EditController& editController, AudioProcessorParameter& p,\r
Vst::ParamID vstParamID, Vst::UnitID vstUnitID,\r
- bool isBypassParameter, bool forceLegacyParamIDs)\r
+ bool isBypassParameter)\r
: owner (editController), param (p)\r
{\r
info.id = vstParamID;\r
info.unitId = vstUnitID;\r
\r
- toString128 (info.title, param.getName (128));\r
- toString128 (info.shortTitle, param.getName (8));\r
- toString128 (info.units, param.getLabel());\r
+ updateParameterInfo();\r
\r
info.stepCount = (Steinberg::int32) 0;\r
\r
- if (! forceLegacyParamIDs && param.isDiscrete())\r
+ #if ! JUCE_FORCE_LEGACY_PARAMETER_AUTOMATION_TYPE\r
+ if (param.isDiscrete())\r
+ #endif\r
{\r
const int numSteps = param.getNumSteps();\r
info.stepCount = (Steinberg::int32) (numSteps > 0 && numSteps < 0x7fffffff ? numSteps - 1 : 0);\r
\r
virtual ~Param() override = default;\r
\r
+ void updateParameterInfo()\r
+ {\r
+ toString128 (info.title, param.getName (128));\r
+ toString128 (info.shortTitle, param.getName (8));\r
+ toString128 (info.units, param.getLabel());\r
+ }\r
+\r
bool setNormalized (Vst::ParamValue v) override\r
{\r
v = jlimit (0.0, 1.0, v);\r
tresult PLUGIN_API getMidiControllerAssignment (Steinberg::int32 /*busIndex*/, Steinberg::int16 channel,\r
Vst::CtrlNumber midiControllerNumber, Vst::ParamID& resultID) override\r
{\r
+ #if JUCE_VST3_EMULATE_MIDI_CC_WITH_PARAMETERS\r
resultID = midiControllerToParameter[channel][midiControllerNumber];\r
-\r
return kResultTrue; // Returning false makes some hosts stop asking for further MIDI Controller Assignments\r
+ #else\r
+ ignoreUnused (channel, midiControllerNumber, resultID);\r
+ return kResultFalse;\r
+ #endif\r
}\r
\r
// Converts an incoming parameter index to a MIDI controller:\r
\r
void audioProcessorChanged (AudioProcessor*) override\r
{\r
+ auto numParameters = parameters.getParameterCount();\r
+\r
+ for (int32 i = 0; i < numParameters; ++i)\r
+ if (auto* param = dynamic_cast<Param*> (parameters.getParameterByIndex (i)))\r
+ param->updateParameterInfo();\r
+\r
if (auto* pluginInstance = getPluginInstance())\r
{\r
if (pluginInstance->getNumPrograms() > 1)\r
}\r
\r
if (componentHandler != nullptr && ! inSetupProcessing)\r
- componentHandler->restartComponent (Vst::kLatencyChanged | Vst::kParamValuesChanged);\r
+ componentHandler->restartComponent (Vst::kLatencyChanged | Vst::kParamValuesChanged | Vst::kParamTitlesChanged);\r
}\r
\r
void parameterValueChanged (int, float newValue) override\r
\r
if (parameters.getParameterCount() <= 0)\r
{\r
- #if JUCE_FORCE_USE_LEGACY_PARAM_IDS\r
- const bool forceLegacyParamIDs = true;\r
- #else\r
- const bool forceLegacyParamIDs = false;\r
- #endif\r
-\r
auto n = audioProcessor->getNumParameters();\r
\r
for (int i = 0; i < n; ++i)\r
auto unitID = JuceAudioProcessor::getUnitID (parameterGroup);\r
\r
parameters.addParameter (new Param (*this, *juceParam, vstParamID, unitID,\r
- (vstParamID == audioProcessor->bypassParamID), forceLegacyParamIDs));\r
+ (vstParamID == audioProcessor->bypassParamID)));\r
}\r
\r
if (pluginInstance->getNumPrograms() > 1)\r
component->addToDesktop (0, parent);\r
component->setOpaque (true);\r
component->setVisible (true);\r
+ #if JUCE_WIN_PER_MONITOR_DPI_AWARE\r
+ component->checkScaleFactorIsCorrect();\r
+ #endif\r
#else\r
isNSView = (strcmp (type, kPlatformTypeNSView) == 0);\r
macHostWindow = juce::attachComponentToWindowRefVST (component.get(), parent, isNSView);\r
pluginInstance->setCurrentProgram (programValue);\r
}\r
#if JUCE_VST3_EMULATE_MIDI_CC_WITH_PARAMETERS\r
- else if (juceVST3EditController->isMidiControllerParamID (vstParamID))\r
+ else if (juceVST3EditController != nullptr && juceVST3EditController->isMidiControllerParamID (vstParamID))\r
addParameterChangeToMidiBuffer (offsetSamples, vstParamID, value);\r
#endif\r
else\r
\r
for (int bus = 0; bus < n && totalOutputChans < plugInOutputChannels; ++bus)\r
{\r
+ if (auto* busObject = pluginInstance->getBus (false, bus))\r
+ if (! busObject->isEnabled())\r
+ continue;\r
+\r
if (bus < vstOutputs)\r
{\r
if (auto** const busChannels = getPointerForAudioBus<FloatType> (data.outputs[bus]))\r
\r
for (int bus = 0; bus < n && totalInputChans < plugInInputChannels; ++bus)\r
{\r
+ if (auto* busObject = pluginInstance->getBus (true, bus))\r
+ if (! busObject->isEnabled())\r
+ continue;\r
+\r
if (bus < vstInputs)\r
{\r
if (auto** const busChannels = getPointerForAudioBus<FloatType> (data.inputs[bus]))\r
==============================================================================\r
*/\r
\r
+\r
/*******************************************************************************\r
The block below describes the properties of this module, and is read by\r
the Projucer to automatically generate project code that uses it.\r
\r
BEGIN_JUCE_MODULE_DECLARATION\r
\r
- ID: juce_audio_plugin_client\r
- vendor: juce\r
- version: 5.4.5\r
- name: JUCE audio plugin wrapper classes\r
- description: Classes for building VST, VST3, AudioUnit, AAX and RTAS plugins.\r
- website: http://www.juce.com/juce\r
- license: GPL/Commercial\r
+ ID: juce_audio_plugin_client\r
+ vendor: juce\r
+ version: 5.4.6\r
+ name: JUCE audio plugin wrapper classes\r
+ description: Classes for building VST, VST3, AudioUnit, AAX and RTAS plugins.\r
+ website: http://www.juce.com/juce\r
+ license: GPL/Commercial\r
\r
- dependencies: juce_gui_basics, juce_audio_basics, juce_audio_processors\r
+ dependencies: juce_gui_basics, juce_audio_basics, juce_audio_processors\r
\r
END_JUCE_MODULE_DECLARATION\r
\r
/** Config: JUCE_USE_STUDIO_ONE_COMPATIBLE_PARAMETERS\r
\r
Enable this if you want JUCE to use parameter ids which are compatible\r
- with Studio One. Studio One ignores any parameter ids which are negative.\r
+ with Studio One, as Studio One ignores any parameter ids which are negative.\r
Enabling this option will make JUCE generate only positive parameter ids.\r
Note that if you have already released a plug-in prior to JUCE 4.3.0 then\r
- enabling this will change your parameter ids making your plug-in\r
- incompatible to old automation data.\r
+ enabling this will change your parameter ids, making your plug-in\r
+ incompatible with old automation data.\r
*/\r
#ifndef JUCE_USE_STUDIO_ONE_COMPATIBLE_PARAMETERS\r
#define JUCE_USE_STUDIO_ONE_COMPATIBLE_PARAMETERS 1\r
#endif\r
\r
+/** Config: JUCE_AU_WRAPPERS_SAVE_PROGRAM_STATES\r
+\r
+ Enable this if you want to receive get/setProgramStateInformation calls,\r
+ instead of get/setStateInformation calls, from the AU and AUv3 plug-in\r
+ wrappers. In JUCE version 5.4.5 and earlier this was the default behaviour,\r
+ so if you have modified the default implementations of get/setProgramStateInformation\r
+ (where the default implementations simply call through to get/setStateInformation)\r
+ then you may need to enable this configuration option to maintain backwards\r
+ compatibility with previously saved state.\r
+*/\r
+#ifndef JUCE_AU_WRAPPERS_SAVE_PROGRAM_STATES\r
+ #define JUCE_AU_WRAPPERS_SAVE_PROGRAM_STATES 0\r
+#endif\r
+\r
/** Config: JUCE_STANDALONE_FILTER_WINDOW_USE_KIOSK_MODE\r
\r
Enable this if you want your standalone plugin window to use kiosk mode.\r
*/\r
\r
#define UseExtendedThingResource 1\r
-#include <AudioUnit/AudioUnit.r>\r
+#include <AudioUnit.r>\r
\r
//==============================================================================\r
/* The AppConfig.h file should be a file in your project, containing info to describe the\r
==============================================================================\r
*/\r
\r
+#if JucePlugin_Build_AU\r
+\r
#ifdef __clang__\r
#pragma clang diagnostic push\r
#pragma clang diagnostic ignored "-Wparentheses"\r
#if __has_warning("-Wnullable-to-nonnull-conversion")\r
#pragma clang diagnostic ignored "-Wnullable-to-nonnull-conversion"\r
#endif\r
+ #if __has_warning("-Wignored-qualifiers")\r
+ #pragma clang diagnostic ignored "-Wignored-qualifiers"\r
+ #endif\r
#endif\r
\r
// From MacOS 10.13 and iOS 11 Apple has (sensibly!) stopped defining a whole\r
#ifdef __clang__\r
#pragma clang diagnostic pop\r
#endif\r
+\r
+#endif\r
==============================================================================\r
*/\r
\r
+#if JucePlugin_Build_Standalone\r
+\r
#if ! JUCE_MODULE_AVAILABLE_juce_audio_utils\r
#error To compile AudioUnitv3 and/or Standalone plug-ins, you need to add the juce_audio_utils and juce_audio_devices modules!\r
#endif\r
#endif\r
\r
JUCE_MAIN_FUNCTION_DEFINITION\r
+\r
+#endif\r
MuseReceptorGeneric, /**< Represents Muse Receptor. */\r
pluginval, /**< Represents pluginval. */\r
Reaper, /**< Represents Cockos Reaper. */\r
+ Reason, /**< Represents Reason. */\r
Renoise, /**< Represents Renoise. */\r
SADiE, /**< Represents SADiE. */\r
SteinbergCubase4, /**< Represents Steinberg Cubase 4. */\r
SteinbergCubase9, /**< Represents Steinberg Cubase 9. */\r
SteinbergCubase9_5, /**< Represents Steinberg Cubase 9.5. */\r
SteinbergCubase10, /**< Represents Steinberg Cubase 10. */\r
+ SteinbergCubase10_5, /**< Represents Steinberg Cubase 10.5. */\r
SteinbergCubaseGeneric, /**< Represents Steinberg Cubase. */\r
SteinbergNuendo3, /**< Represents Steinberg Nuendo 3. */\r
SteinbergNuendo4, /**< Represents Steinberg Nuendo 4. */\r
TracktionGeneric, /**< Represents Tracktion. */\r
TracktionWaveform, /**< Represents Tracktion Waveform. */\r
VBVSTScanner, /**< Represents VB Audio VST Scanner. */\r
+ ViennaEnsemblePro, /**< Represents Vienna Ensemble Pro. */\r
WaveBurner /**< Represents Apple WaveBurner. */\r
};\r
\r
\r
//==============================================================================\r
/** Returns true if the host is any version of Ableton Live. */\r
- bool isAbletonLive() const noexcept { return type == AbletonLive6 || type == AbletonLive7 || type == AbletonLive8 || type == AbletonLive9 || type == AbletonLive10 || type == AbletonLiveGeneric; }\r
+ bool isAbletonLive() const noexcept { return type == AbletonLive6 || type == AbletonLive7 || type == AbletonLive8\r
+ || type == AbletonLive9 || type == AbletonLive10 || type == AbletonLiveGeneric; }\r
/** Returns true if the host is Adobe Audition. */\r
bool isAdobeAudition() const noexcept { return type == AdobeAudition; }\r
/** Returns true if the host is Ardour. */\r
/** Returns true if the host is Bitwig Studio. */\r
bool isBitwigStudio() const noexcept { return type == BitwigStudio; }\r
/** Returns true if the host is any version of Steinberg Cubase. */\r
- 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; }\r
+ bool isCubase() const noexcept { return type == SteinbergCubase4 || type == SteinbergCubase5 || type == SteinbergCubase5Bridged || type == SteinbergCubase6\r
+ || type == SteinbergCubase7 || type == SteinbergCubase8 || type == SteinbergCubase8_5 || type == SteinbergCubase9\r
+ || type == SteinbergCubase9_5 || type == SteinbergCubase10 || type == SteinbergCubase10_5 || type == SteinbergCubaseGeneric; }\r
/** Returns true if the host is Steinberg Cubase 7 or later. */\r
bool isCubase7orLater() const noexcept { return isCubase() && ! (type == SteinbergCubase4 || type == SteinbergCubase5 || type == SteinbergCubase6); }\r
/** Returns true if the host is Steinberg Cubase 5 Bridged. */\r
bool isReceptor() const noexcept { return type == MuseReceptorGeneric; }\r
/** Returns true if the host is Cockos Reaper. */\r
bool isReaper() const noexcept { return type == Reaper; }\r
+ /** Returns true if the host is Reason. */\r
+ bool isReason() const noexcept { return type == Reason; }\r
/** Returns true if the host is Renoise. */\r
bool isRenoise() const noexcept { return type == Renoise; }\r
/** Returns true if the host is SADiE. */\r
bool isTracktionWaveform() const noexcept { return type == TracktionWaveform; }\r
/** Returns true if the host is VB Audio VST Scanner. */\r
bool isVBVSTScanner() const noexcept { return type == VBVSTScanner; }\r
+ /** Returns true if the host is Vienna Ensemble Pro. */\r
+ bool isViennaEnsemblePro() const noexcept { return type == ViennaEnsemblePro; }\r
/** Returns true if the host is Apple WaveBurner. */\r
bool isWaveBurner() const noexcept { return type == WaveBurner; }\r
/** Returns true if the host is any version of Steinberg WaveLab. */\r
case MergingPyramix: return "Pyramix";\r
case MuseReceptorGeneric: return "Muse Receptor";\r
case Reaper: return "Reaper";\r
+ case Reason: return "Reason";\r
case Renoise: return "Renoise";\r
case SADiE: return "SADiE";\r
case SteinbergCubase4: return "Steinberg Cubase 4";\r
case SteinbergCubase9: return "Steinberg Cubase 9";\r
case SteinbergCubase9_5: return "Steinberg Cubase 9.5";\r
case SteinbergCubase10: return "Steinberg Cubase 10";\r
+ case SteinbergCubase10_5: return "Steinberg Cubase 10.5";\r
case SteinbergCubaseGeneric: return "Steinberg Cubase";\r
case SteinbergNuendo3: return "Steinberg Nuendo 3";\r
case SteinbergNuendo4: return "Steinberg Nuendo 4";\r
case TracktionGeneric: return "Tracktion";\r
case TracktionWaveform: return "Tracktion Waveform";\r
case VBVSTScanner: return "VBVSTScanner";\r
+ case ViennaEnsemblePro: return "Vienna Ensemble Pro";\r
case WaveBurner: return "WaveBurner";\r
default: break;\r
}\r
auto hostFilename = File (hostPath).getFileName();\r
\r
#if JUCE_MAC\r
- if (hostPath.containsIgnoreCase ("Final Cut Pro.app")) return FinalCut;\r
- if (hostPath.containsIgnoreCase ("Final Cut Pro Trial.app")) return FinalCut;\r
- if (hostPath.containsIgnoreCase ("Live 6.")) return AbletonLive6;\r
- if (hostPath.containsIgnoreCase ("Live 7.")) return AbletonLive7;\r
- if (hostPath.containsIgnoreCase ("Live 8.")) return AbletonLive8;\r
- if (hostPath.containsIgnoreCase ("Live 9.")) return AbletonLive9;\r
- if (hostPath.containsIgnoreCase ("Live 10.")) return AbletonLive10;\r
- if (hostFilename.containsIgnoreCase ("Live")) return AbletonLiveGeneric;\r
- if (hostFilename.containsIgnoreCase ("Adobe Premiere")) return AdobePremierePro;\r
- if (hostFilename.containsIgnoreCase ("GarageBand")) return AppleGarageBand;\r
- if (hostFilename.containsIgnoreCase ("Logic")) return AppleLogic;\r
- if (hostFilename.containsIgnoreCase ("MainStage")) return AppleMainStage;\r
- if (hostFilename.containsIgnoreCase ("Pro Tools")) return AvidProTools;\r
- if (hostFilename.containsIgnoreCase ("Nuendo 3")) return SteinbergNuendo3;\r
- if (hostFilename.containsIgnoreCase ("Nuendo 4")) return SteinbergNuendo4;\r
- if (hostFilename.containsIgnoreCase ("Nuendo 5")) return SteinbergNuendo5;\r
- if (hostFilename.containsIgnoreCase ("Nuendo")) return SteinbergNuendoGeneric;\r
- if (hostFilename.containsIgnoreCase ("Cubase 4")) return SteinbergCubase4;\r
- if (hostFilename.containsIgnoreCase ("Cubase 5")) return SteinbergCubase5;\r
- if (hostFilename.containsIgnoreCase ("Cubase 6")) return SteinbergCubase6;\r
- if (hostFilename.containsIgnoreCase ("Cubase 7")) return SteinbergCubase7;\r
- if (hostPath.containsIgnoreCase ("Cubase 8.app")) return SteinbergCubase8;\r
- if (hostPath.containsIgnoreCase ("Cubase 8.5.app")) return SteinbergCubase8_5;\r
- if (hostPath.containsIgnoreCase ("Cubase 9.app")) return SteinbergCubase9;\r
- if (hostPath.containsIgnoreCase ("Cubase 9.5.app")) return SteinbergCubase9_5;\r
- if (hostPath.containsIgnoreCase ("Cubase 10.app")) return SteinbergCubase10;\r
- if (hostFilename.containsIgnoreCase ("Cubase")) return SteinbergCubaseGeneric;\r
- if (hostPath.containsIgnoreCase ("Wavelab 7")) return SteinbergWavelab7;\r
- if (hostPath.containsIgnoreCase ("Wavelab 8")) return SteinbergWavelab8;\r
- if (hostFilename.containsIgnoreCase ("Wavelab")) return SteinbergWavelabGeneric;\r
- if (hostFilename.containsIgnoreCase ("WaveBurner")) return WaveBurner;\r
- if (hostPath.containsIgnoreCase ("Digital Performer")) return DigitalPerformer;\r
- if (hostFilename.containsIgnoreCase ("reaper")) return Reaper;\r
- if (hostPath.containsIgnoreCase ("Studio One")) return StudioOne;\r
- if (hostFilename.startsWithIgnoreCase ("Waveform")) return TracktionWaveform;\r
- if (hostPath.containsIgnoreCase ("Tracktion 3")) return Tracktion3;\r
- if (hostFilename.containsIgnoreCase ("Tracktion")) return TracktionGeneric;\r
- if (hostFilename.containsIgnoreCase ("Renoise")) return Renoise;\r
- if (hostFilename.containsIgnoreCase ("Resolve")) return DaVinciResolve;\r
- if (hostFilename.startsWith ("Bitwig")) return BitwigStudio;\r
- if (hostFilename.containsIgnoreCase ("OsxFL")) return FruityLoops;\r
- if (hostFilename.containsIgnoreCase ("pluginval")) return pluginval;\r
- if (hostFilename.containsIgnoreCase ("AudioPluginHost")) return JUCEPluginHost;\r
+ if (hostPath.containsIgnoreCase ("Final Cut Pro.app")) return FinalCut;\r
+ if (hostPath.containsIgnoreCase ("Final Cut Pro Trial.app")) return FinalCut;\r
+ if (hostPath.containsIgnoreCase ("Live 6")) return AbletonLive6;\r
+ if (hostPath.containsIgnoreCase ("Live 7")) return AbletonLive7;\r
+ if (hostPath.containsIgnoreCase ("Live 8")) return AbletonLive8;\r
+ if (hostPath.containsIgnoreCase ("Live 9")) return AbletonLive9;\r
+ if (hostPath.containsIgnoreCase ("Live 10")) return AbletonLive10;\r
+ if (hostFilename.containsIgnoreCase ("Live")) return AbletonLiveGeneric;\r
+ if (hostFilename.containsIgnoreCase ("Adobe Premiere")) return AdobePremierePro;\r
+ if (hostFilename.containsIgnoreCase ("GarageBand")) return AppleGarageBand;\r
+ if (hostFilename.containsIgnoreCase ("Logic")) return AppleLogic;\r
+ if (hostFilename.containsIgnoreCase ("MainStage")) return AppleMainStage;\r
+ if (hostFilename.containsIgnoreCase ("Pro Tools")) return AvidProTools;\r
+ if (hostFilename.containsIgnoreCase ("Nuendo 3")) return SteinbergNuendo3;\r
+ if (hostFilename.containsIgnoreCase ("Nuendo 4")) return SteinbergNuendo4;\r
+ if (hostFilename.containsIgnoreCase ("Nuendo 5")) return SteinbergNuendo5;\r
+ if (hostFilename.containsIgnoreCase ("Nuendo")) return SteinbergNuendoGeneric;\r
+ if (hostFilename.containsIgnoreCase ("Cubase 4")) return SteinbergCubase4;\r
+ if (hostFilename.containsIgnoreCase ("Cubase 5")) return SteinbergCubase5;\r
+ if (hostFilename.containsIgnoreCase ("Cubase 6")) return SteinbergCubase6;\r
+ if (hostFilename.containsIgnoreCase ("Cubase 7")) return SteinbergCubase7;\r
+ if (hostPath.containsIgnoreCase ("Cubase 8.app")) return SteinbergCubase8;\r
+ if (hostPath.containsIgnoreCase ("Cubase 8.5.app")) return SteinbergCubase8_5;\r
+ if (hostPath.containsIgnoreCase ("Cubase 9.app")) return SteinbergCubase9;\r
+ if (hostPath.containsIgnoreCase ("Cubase 9.5.app")) return SteinbergCubase9_5;\r
+ if (hostPath.containsIgnoreCase ("Cubase 10.app")) return SteinbergCubase10;\r
+ if (hostPath.containsIgnoreCase ("Cubase 10.5.app")) return SteinbergCubase10_5;\r
+ if (hostFilename.containsIgnoreCase ("Cubase")) return SteinbergCubaseGeneric;\r
+ if (hostPath.containsIgnoreCase ("Wavelab 7")) return SteinbergWavelab7;\r
+ if (hostPath.containsIgnoreCase ("Wavelab 8")) return SteinbergWavelab8;\r
+ if (hostFilename.containsIgnoreCase ("Wavelab")) return SteinbergWavelabGeneric;\r
+ if (hostFilename.containsIgnoreCase ("WaveBurner")) return WaveBurner;\r
+ if (hostPath.containsIgnoreCase ("Digital Performer")) return DigitalPerformer;\r
+ if (hostFilename.containsIgnoreCase ("reaper")) return Reaper;\r
+ if (hostFilename.containsIgnoreCase ("Reason")) return Reason;\r
+ if (hostPath.containsIgnoreCase ("Studio One")) return StudioOne;\r
+ if (hostFilename.startsWithIgnoreCase ("Waveform")) return TracktionWaveform;\r
+ if (hostPath.containsIgnoreCase ("Tracktion 3")) return Tracktion3;\r
+ if (hostFilename.containsIgnoreCase ("Tracktion")) return TracktionGeneric;\r
+ if (hostFilename.containsIgnoreCase ("Renoise")) return Renoise;\r
+ if (hostFilename.containsIgnoreCase ("Resolve")) return DaVinciResolve;\r
+ if (hostFilename.startsWith ("Bitwig")) return BitwigStudio;\r
+ if (hostFilename.containsIgnoreCase ("OsxFL")) return FruityLoops;\r
+ if (hostFilename.containsIgnoreCase ("pluginval")) return pluginval;\r
+ if (hostFilename.containsIgnoreCase ("AudioPluginHost")) return JUCEPluginHost;\r
+ if (hostFilename.containsIgnoreCase ("Vienna Ensemble Pro")) return ViennaEnsemblePro;\r
\r
#elif JUCE_WINDOWS\r
- if (hostFilename.containsIgnoreCase ("Live 6.")) return AbletonLive6;\r
- if (hostFilename.containsIgnoreCase ("Live 7.")) return AbletonLive7;\r
- if (hostFilename.containsIgnoreCase ("Live 8.")) return AbletonLive8;\r
- if (hostFilename.containsIgnoreCase ("Live 9.")) return AbletonLive9;\r
- if (hostFilename.containsIgnoreCase ("Live 10.")) return AbletonLive10;\r
- if (hostFilename.containsIgnoreCase ("Live ")) return AbletonLiveGeneric;\r
- if (hostFilename.containsIgnoreCase ("Audition")) return AdobeAudition;\r
- if (hostFilename.containsIgnoreCase ("Adobe Premiere")) return AdobePremierePro;\r
- if (hostFilename.containsIgnoreCase ("ProTools")) return AvidProTools;\r
- if (hostPath.containsIgnoreCase ("SONAR 8")) return CakewalkSonar8;\r
- if (hostFilename.containsIgnoreCase ("SONAR")) return CakewalkSonarGeneric;\r
- if (hostFilename.containsIgnoreCase ("Cakewalk.exe")) return CakewalkByBandlab;\r
- if (hostFilename.containsIgnoreCase ("GarageBand")) return AppleGarageBand;\r
- if (hostFilename.containsIgnoreCase ("Logic")) return AppleLogic;\r
- if (hostFilename.containsIgnoreCase ("MainStage")) return AppleMainStage;\r
- if (hostFilename.startsWithIgnoreCase ("Waveform")) return TracktionWaveform;\r
- if (hostPath.containsIgnoreCase ("Tracktion 3")) return Tracktion3;\r
- if (hostFilename.containsIgnoreCase ("Tracktion")) return TracktionGeneric;\r
- if (hostFilename.containsIgnoreCase ("reaper")) return Reaper;\r
- if (hostFilename.containsIgnoreCase ("Cubase4")) return SteinbergCubase4;\r
- if (hostFilename.containsIgnoreCase ("Cubase5")) return SteinbergCubase5;\r
- if (hostFilename.containsIgnoreCase ("Cubase6")) return SteinbergCubase6;\r
- if (hostFilename.containsIgnoreCase ("Cubase7")) return SteinbergCubase7;\r
- if (hostFilename.containsIgnoreCase ("Cubase8.exe")) return SteinbergCubase8;\r
- if (hostFilename.containsIgnoreCase ("Cubase8.5.exe")) return SteinbergCubase8_5;\r
+ if (hostFilename.containsIgnoreCase ("Live 6")) return AbletonLive6;\r
+ if (hostFilename.containsIgnoreCase ("Live 7")) return AbletonLive7;\r
+ if (hostFilename.containsIgnoreCase ("Live 8")) return AbletonLive8;\r
+ if (hostFilename.containsIgnoreCase ("Live 9")) return AbletonLive9;\r
+ if (hostFilename.containsIgnoreCase ("Live 10")) return AbletonLive10;\r
+ if (hostFilename.containsIgnoreCase ("Live ")) return AbletonLiveGeneric;\r
+ if (hostFilename.containsIgnoreCase ("Audition")) return AdobeAudition;\r
+ if (hostFilename.containsIgnoreCase ("Adobe Premiere")) return AdobePremierePro;\r
+ if (hostFilename.containsIgnoreCase ("ProTools")) return AvidProTools;\r
+ if (hostPath.containsIgnoreCase ("SONAR 8")) return CakewalkSonar8;\r
+ if (hostFilename.containsIgnoreCase ("SONAR")) return CakewalkSonarGeneric;\r
+ if (hostFilename.containsIgnoreCase ("Cakewalk.exe")) return CakewalkByBandlab;\r
+ if (hostFilename.containsIgnoreCase ("GarageBand")) return AppleGarageBand;\r
+ if (hostFilename.containsIgnoreCase ("Logic")) return AppleLogic;\r
+ if (hostFilename.containsIgnoreCase ("MainStage")) return AppleMainStage;\r
+ if (hostFilename.startsWithIgnoreCase ("Waveform")) return TracktionWaveform;\r
+ if (hostPath.containsIgnoreCase ("Tracktion 3")) return Tracktion3;\r
+ if (hostFilename.containsIgnoreCase ("Tracktion")) return TracktionGeneric;\r
+ if (hostFilename.containsIgnoreCase ("reaper")) return Reaper;\r
+ if (hostFilename.containsIgnoreCase ("Cubase4")) return SteinbergCubase4;\r
+ if (hostFilename.containsIgnoreCase ("Cubase5")) return SteinbergCubase5;\r
+ if (hostFilename.containsIgnoreCase ("Cubase6")) return SteinbergCubase6;\r
+ if (hostFilename.containsIgnoreCase ("Cubase7")) return SteinbergCubase7;\r
+ if (hostFilename.containsIgnoreCase ("Cubase8.exe")) return SteinbergCubase8;\r
+ if (hostFilename.containsIgnoreCase ("Cubase8.5.exe")) return SteinbergCubase8_5;\r
// Later version of Cubase scan plug-ins with a separate executable "vst2xscanner"\r
if (hostFilename.containsIgnoreCase ("Cubase9.5.exe")\r
- || hostPath.containsIgnoreCase ("Cubase 9.5")) return SteinbergCubase9_5;\r
+ || hostPath.containsIgnoreCase ("Cubase 9.5")) return SteinbergCubase9_5;\r
if (hostFilename.containsIgnoreCase ("Cubase9.exe")\r
- || hostPath.containsIgnoreCase ("Cubase 9")) return SteinbergCubase9;\r
+ || hostPath.containsIgnoreCase ("Cubase 9")) return SteinbergCubase9;\r
+ if (hostFilename.containsIgnoreCase ("Cubase10.5.exe")\r
+ || hostPath.containsIgnoreCase ("Cubase 10.5")) return SteinbergCubase10_5;\r
if (hostFilename.containsIgnoreCase ("Cubase10.exe")\r
- || hostPath.containsIgnoreCase ("Cubase 10")) return SteinbergCubase10;\r
- if (hostFilename.containsIgnoreCase ("Cubase")) return SteinbergCubaseGeneric;\r
- if (hostFilename.containsIgnoreCase ("VSTBridgeApp")) return SteinbergCubase5Bridged;\r
- if (hostPath.containsIgnoreCase ("Wavelab 5")) return SteinbergWavelab5;\r
- if (hostPath.containsIgnoreCase ("Wavelab 6")) return SteinbergWavelab6;\r
- if (hostPath.containsIgnoreCase ("Wavelab 7")) return SteinbergWavelab7;\r
- if (hostPath.containsIgnoreCase ("Wavelab 8")) return SteinbergWavelab8;\r
- if (hostPath.containsIgnoreCase ("Nuendo")) return SteinbergNuendoGeneric;\r
- if (hostFilename.containsIgnoreCase ("Wavelab")) return SteinbergWavelabGeneric;\r
- if (hostFilename.containsIgnoreCase ("TestHost")) return SteinbergTestHost;\r
- if (hostFilename.containsIgnoreCase ("rm-host")) return MuseReceptorGeneric;\r
- if (hostFilename.startsWith ("FL")) return FruityLoops;\r
- if (hostFilename.contains ("ilbridge.")) return FruityLoops;\r
- if (hostPath.containsIgnoreCase ("Studio One")) return StudioOne;\r
- if (hostPath.containsIgnoreCase ("Digital Performer")) return DigitalPerformer;\r
- if (hostFilename.containsIgnoreCase ("VST_Scanner")) return VBVSTScanner;\r
- if (hostPath.containsIgnoreCase ("Merging Technologies")) return MergingPyramix;\r
- if (hostFilename.startsWithIgnoreCase ("Sam")) return MagixSamplitude;\r
- if (hostFilename.startsWithIgnoreCase ("Sequoia")) return MagixSequoia;\r
- if (hostFilename.containsIgnoreCase ("Renoise")) return Renoise;\r
- if (hostFilename.containsIgnoreCase ("Resolve")) return DaVinciResolve;\r
- if (hostPath.containsIgnoreCase ("Bitwig Studio")) return BitwigStudio;\r
- if (hostFilename.containsIgnoreCase ("Sadie")) return SADiE;\r
- if (hostFilename.containsIgnoreCase ("pluginval")) return pluginval;\r
- if (hostFilename.containsIgnoreCase ("AudioPluginHost")) return JUCEPluginHost;\r
+ || hostPath.containsIgnoreCase ("Cubase 10")) return SteinbergCubase10;\r
+ if (hostFilename.containsIgnoreCase ("Cubase")) return SteinbergCubaseGeneric;\r
+ if (hostFilename.containsIgnoreCase ("VSTBridgeApp")) return SteinbergCubase5Bridged;\r
+ if (hostPath.containsIgnoreCase ("Wavelab 5")) return SteinbergWavelab5;\r
+ if (hostPath.containsIgnoreCase ("Wavelab 6")) return SteinbergWavelab6;\r
+ if (hostPath.containsIgnoreCase ("Wavelab 7")) return SteinbergWavelab7;\r
+ if (hostPath.containsIgnoreCase ("Wavelab 8")) return SteinbergWavelab8;\r
+ if (hostPath.containsIgnoreCase ("Nuendo")) return SteinbergNuendoGeneric;\r
+ if (hostFilename.containsIgnoreCase ("Wavelab")) return SteinbergWavelabGeneric;\r
+ if (hostFilename.containsIgnoreCase ("TestHost")) return SteinbergTestHost;\r
+ if (hostFilename.containsIgnoreCase ("rm-host")) return MuseReceptorGeneric;\r
+ if (hostFilename.startsWith ("FL")) return FruityLoops;\r
+ if (hostFilename.contains ("ilbridge.")) return FruityLoops;\r
+ if (hostPath.containsIgnoreCase ("Studio One")) return StudioOne;\r
+ if (hostPath.containsIgnoreCase ("Digital Performer")) return DigitalPerformer;\r
+ if (hostFilename.containsIgnoreCase ("VST_Scanner")) return VBVSTScanner;\r
+ if (hostPath.containsIgnoreCase ("Merging Technologies")) return MergingPyramix;\r
+ if (hostFilename.startsWithIgnoreCase ("Sam")) return MagixSamplitude;\r
+ if (hostFilename.startsWithIgnoreCase ("Sequoia")) return MagixSequoia;\r
+ if (hostFilename.containsIgnoreCase ("Reason")) return Reason;\r
+ if (hostFilename.containsIgnoreCase ("Renoise")) return Renoise;\r
+ if (hostFilename.containsIgnoreCase ("Resolve")) return DaVinciResolve;\r
+ if (hostPath.containsIgnoreCase ("Bitwig Studio")) return BitwigStudio;\r
+ if (hostFilename.containsIgnoreCase ("Sadie")) return SADiE;\r
+ if (hostFilename.containsIgnoreCase ("pluginval")) return pluginval;\r
+ if (hostFilename.containsIgnoreCase ("AudioPluginHost")) return JUCEPluginHost;\r
+ if (hostFilename.containsIgnoreCase ("Vienna Ensemble Pro")) return ViennaEnsemblePro;\r
\r
#elif JUCE_LINUX\r
if (hostFilename.containsIgnoreCase ("Ardour")) return Ardour;\r
errorMessage string.\r
\r
If you intend to instantiate a AudioUnit v3 plug-in then you must either\r
- use the non-blocking asynchrous version below - or call this method from a\r
+ use the non-blocking asynchronous version below - or call this method from a\r
thread other than the message thread and without blocking the message\r
thread.\r
*/\r
all the formats that this manager knows about.\r
\r
The caller must supply a callback object which will be called when\r
- the instantantiation has completed.\r
+ the instantiation has completed.\r
\r
If it can't load the plugin then the callback function will be called\r
passing a nullptr as the instance argument along with an error message.\r
the callback function.\r
\r
If you intend to instantiate a AudioUnit v3 plug-in then you must use\r
- this non-blocking asynchrous version - or call the synchrous method\r
+ this non-blocking asynchronous version - or call the synchronous method\r
from an auxiliary thread.\r
*/\r
void createPluginInstanceAsync (const PluginDescription& description,\r
UseResFile (resFileId);\r
\r
const OSType thngType = stringToOSType ("thng");\r
+ auto numResources = Count1Resources (thngType);\r
\r
- for (ResourceIndex i = 1; i <= Count1Resources (thngType); ++i)\r
+ if (numResources > 0)\r
{\r
- if (Handle h = Get1IndResource (thngType, i))\r
+ for (ResourceIndex i = 1; i <= numResources; ++i)\r
{\r
- HLock (h);\r
- const uint32* const types = (const uint32*) *h;\r
-\r
- if (types[0] == kAudioUnitType_MusicDevice\r
- || types[0] == kAudioUnitType_MusicEffect\r
- || types[0] == kAudioUnitType_Effect\r
- || types[0] == kAudioUnitType_Generator\r
- || types[0] == kAudioUnitType_Panner\r
- || types[0] == kAudioUnitType_Mixer\r
- || types[0] == kAudioUnitType_MIDIProcessor)\r
+ if (Handle h = Get1IndResource (thngType, i))\r
{\r
- desc.componentType = types[0];\r
- desc.componentSubType = types[1];\r
- desc.componentManufacturer = types[2];\r
+ HLock (h);\r
+ const uint32* const types = (const uint32*) *h;\r
+\r
+ if (types[0] == kAudioUnitType_MusicDevice\r
+ || types[0] == kAudioUnitType_MusicEffect\r
+ || types[0] == kAudioUnitType_Effect\r
+ || types[0] == kAudioUnitType_Generator\r
+ || types[0] == kAudioUnitType_Panner\r
+ || types[0] == kAudioUnitType_Mixer\r
+ || types[0] == kAudioUnitType_MIDIProcessor)\r
+ {\r
+ desc.componentType = types[0];\r
+ desc.componentSubType = types[1];\r
+ desc.componentManufacturer = types[2];\r
\r
- if (AudioComponent comp = AudioComponentFindNext (nullptr, &desc))\r
- getNameAndManufacturer (comp, name, manufacturer);\r
+ if (AudioComponent comp = AudioComponentFindNext (nullptr, &desc))\r
+ getNameAndManufacturer (comp, name, manufacturer);\r
\r
- break;\r
- }\r
+ break;\r
+ }\r
\r
- HUnlock (h);\r
- ReleaseResource (h);\r
+ HUnlock (h);\r
+ ReleaseResource (h);\r
+ }\r
}\r
}\r
+ else\r
+ {\r
+ NSBundle* bundle = [[NSBundle alloc] initWithPath: (NSString*) fileOrIdentifier.toCFString()];\r
+\r
+ NSArray* audioComponents = [bundle objectForInfoDictionaryKey: @"AudioComponents"];\r
+ NSDictionary* dict = audioComponents[0];\r
+\r
+ desc.componentManufacturer = stringToOSType (nsStringToJuce ((NSString*) [dict valueForKey: @"manufacturer"]));\r
+ desc.componentType = stringToOSType (nsStringToJuce ((NSString*) [dict valueForKey: @"type"]));\r
+ desc.componentSubType = stringToOSType (nsStringToJuce ((NSString*) [dict valueForKey: @"subtype"]));\r
+\r
+ [bundle release];\r
+ }\r
\r
CFBundleCloseBundleResourceMap (bundleRef, resFileId);\r
CFRelease (bundleRef);\r
\r
// try to convert the layout into a tag\r
actualTag = CoreAudioLayouts::toCoreAudio (CoreAudioLayouts::fromCoreAudio (layout));\r
- }\r
\r
- if (actualTag != requestedTag)\r
- {\r
- zerostruct (layout);\r
- layout.mChannelLayoutTag = requestedTag;\r
+ if (actualTag != requestedTag)\r
+ {\r
+ zerostruct (layout);\r
+ layout.mChannelLayoutTag = requestedTag;\r
\r
- err = AudioUnitSetProperty (audioUnit, kAudioUnitProperty_AudioChannelLayout, scope, static_cast<UInt32> (i), &layout, minDataSize);\r
+ err = AudioUnitSetProperty (audioUnit, kAudioUnitProperty_AudioChannelLayout, scope, static_cast<UInt32> (i), &layout, minDataSize);\r
\r
- // only bail out if the plug-in claims to support layouts\r
- // See AudioUnit headers on kAudioUnitProperty_AudioChannelLayout\r
- if (err != noErr && supportsLayouts && isInitialized)\r
- return false;\r
+ // only bail out if the plug-in claims to support layouts\r
+ // See AudioUnit headers on kAudioUnitProperty_AudioChannelLayout\r
+ if (err != noErr && supportsLayouts && isInitialized)\r
+ return false;\r
+ }\r
}\r
}\r
}\r
{\r
AUPreset current;\r
current.presetNumber = newIndex;\r
- current.presetName = CFSTR("");\r
+\r
+ CFArrayRef presets;\r
+ UInt32 sz = sizeof (CFArrayRef);\r
+\r
+ if (AudioUnitGetProperty (audioUnit, kAudioUnitProperty_FactoryPresets,\r
+ kAudioUnitScope_Global, 0, &presets, &sz) == noErr)\r
+ {\r
+ if (auto* p = (const AUPreset*) CFArrayGetValueAtIndex (presets, newIndex))\r
+ current.presetName = p->presetName;\r
+\r
+ CFRelease (presets);\r
+ }\r
\r
AudioUnitSetProperty (audioUnit, kAudioUnitProperty_PresentPreset,\r
kAudioUnitScope_Global, 0, ¤t, sizeof (AUPreset));\r
CFArrayRef presets;\r
UInt32 sz = sizeof (CFArrayRef);\r
\r
- if (AudioUnitGetProperty (audioUnit, kAudioUnitProperty_FactoryPresets,\r
- kAudioUnitScope_Global, 0, &presets, &sz) == noErr)\r
+ if (index == -1)\r
+ {\r
+ AUPreset current;\r
+ current.presetNumber = -1;\r
+ current.presetName = CFSTR("");\r
+\r
+ UInt32 prstsz = sizeof (AUPreset);\r
+\r
+ AudioUnitGetProperty (audioUnit, kAudioUnitProperty_PresentPreset,\r
+ kAudioUnitScope_Global, 0, ¤t, &prstsz);\r
+\r
+ s = String::fromCFString (current.presetName);\r
+ }\r
+ else if (AudioUnitGetProperty (audioUnit, kAudioUnitProperty_FactoryPresets,\r
+ kAudioUnitScope_Global, 0, &presets, &sz) == noErr)\r
{\r
for (CFIndex i = 0; i < CFArrayGetCount (presets); ++i)\r
{\r
- if (const AUPreset* p = (const AUPreset*) CFArrayGetValueAtIndex (presets, i))\r
+ if (auto* p = (const AUPreset*) CFArrayGetValueAtIndex (presets, i))\r
{\r
if (p->presetNumber == index)\r
{\r
\r
default:\r
if (event.mArgument.mProperty.mPropertyID == kAudioUnitProperty_ParameterList)\r
+ {\r
updateHostDisplay();\r
+ }\r
else if (event.mArgument.mProperty.mPropertyID == kAudioUnitProperty_PresentPreset)\r
+ {\r
sendAllParametersChangedEvents();\r
+ updateHostDisplay();\r
+ }\r
else if (event.mArgument.mProperty.mPropertyID == kAudioUnitProperty_Latency)\r
+ {\r
updateLatency();\r
+ }\r
else if (event.mArgument.mProperty.mPropertyID == kAudioUnitProperty_BypassEffect)\r
+ {\r
if (bypassParam != nullptr)\r
bypassParam->setValueNotifyingHost (bypassParam->getValue());\r
+ }\r
\r
break;\r
}\r
}\r
}\r
\r
- Steinberg::Vst::Event e = { 0 };\r
+ Steinberg::Vst::Event e{};\r
\r
if (msg.isNoteOn())\r
{\r
#if __has_warning("-Wcast-align")\r
#pragma clang diagnostic ignored "-Wcast-align"\r
#endif\r
+ #if __has_warning("-Wignored-qualifiers")\r
+ #pragma clang diagnostic ignored "-Wignored-qualifiers"\r
+ #endif\r
+ #if __has_warning("-Wmissing-field-initializers")\r
+ #pragma clang diagnostic ignored "-Wmissing-field-initializers"\r
+ #endif\r
#endif\r
\r
#undef DEVELOPMENT\r
}\r
}\r
\r
- result = performOnDescription (desc);\r
+ if (desc.uid != 0)\r
+ result = performOnDescription (desc);\r
\r
if (result.failed())\r
break;\r
struct VST3Parameter final : public Parameter\r
{\r
VST3Parameter (VST3PluginInstance& parent,\r
+ int vstParameterIndex,\r
Steinberg::Vst::ParamID parameterID,\r
bool parameterIsAutomatable)\r
: pluginInstance (parent),\r
+ vstParamIndex (vstParameterIndex),\r
paramID (parameterID),\r
automatable (parameterIsAutomatable)\r
{\r
return Parameter::getValueForText (text);\r
}\r
\r
+ Vst::ParameterInfo getParameterInfo() const\r
+ {\r
+ return pluginInstance.getParameterInfoForIndex (vstParamIndex);\r
+ }\r
+\r
float getDefaultValue() const override\r
{\r
- return (float) pluginInstance.getParameterInfoForIndex (getParameterIndex()).defaultNormalizedValue;\r
+ return (float) getParameterInfo().defaultNormalizedValue;\r
}\r
\r
String getName (int /*maximumStringLength*/) const override\r
{\r
- return toString (pluginInstance.getParameterInfoForIndex (getParameterIndex()).title);\r
+ return toString (getParameterInfo().title);\r
}\r
\r
String getLabel() const override\r
{\r
- return toString (pluginInstance.getParameterInfoForIndex (getParameterIndex()).units);\r
+ return toString (getParameterInfo().units);\r
}\r
\r
bool isAutomatable() const override\r
\r
int getNumSteps() const override\r
{\r
- auto stepCount = pluginInstance.getParameterInfoForIndex (getParameterIndex()).stepCount;\r
+ auto stepCount = getParameterInfo().stepCount;\r
return stepCount == 0 ? AudioProcessor::getDefaultNumParameterSteps()\r
: stepCount + 1;\r
}\r
}\r
\r
VST3PluginInstance& pluginInstance;\r
+ const int vstParamIndex;\r
const Steinberg::Vst::ParamID paramID;\r
const bool automatable;\r
};\r
VST3PluginInstance (VST3ComponentHolder* componentHolder)\r
: AudioPluginInstance (getBusProperties (componentHolder->component)),\r
holder (componentHolder),\r
- inputParameterChanges (new ParamValueQueueList()),\r
+ inputParameterChanges (new ParamValueQueueList()),\r
outputParameterChanges (new ParamValueQueueList()),\r
midiInputs (new MidiEventList()),\r
midiOutputs (new MidiEventList())\r
JUCE_DECLARE_VST3_COM_REF_METHODS\r
JUCE_DECLARE_VST3_COM_QUERY_METHODS\r
\r
- Steinberg::int32 PLUGIN_API getParameterCount() override { return numQueuesUsed; }\r
- Vst::IParamValueQueue* PLUGIN_API getParameterData (Steinberg::int32 index) override { return isPositiveAndBelow (static_cast<int> (index), numQueuesUsed) ? queues[(int) index] : nullptr; }\r
+ Steinberg::int32 PLUGIN_API getParameterCount() override\r
+ {\r
+ const ScopedLock sl (queuesLock);\r
+ return numQueuesUsed;\r
+ }\r
+\r
+ Vst::IParamValueQueue* PLUGIN_API getParameterData (Steinberg::int32 index) override\r
+ {\r
+ const ScopedLock sl (queuesLock);\r
+ return isPositiveAndBelow (static_cast<int> (index), numQueuesUsed) ? queues[(int) index] : nullptr;\r
+ }\r
\r
Vst::IParamValueQueue* PLUGIN_API addParameterData (const Vst::ParamID& id, Steinberg::int32& index) override\r
{\r
+ const ScopedLock sl (queuesLock);\r
+\r
for (int i = numQueuesUsed; --i >= 0;)\r
{\r
- if (queues.getUnchecked (i)->getParameterId() == id)\r
+ if (auto* q = queues.getUnchecked (i))\r
{\r
- index = (Steinberg::int32) i;\r
- return queues.getUnchecked (i);\r
+ if (q->getParameterId() == id)\r
+ {\r
+ index = (Steinberg::int32) i;\r
+ return q;\r
+ }\r
}\r
}\r
\r
index = numQueuesUsed++;\r
- ParamValueQueue* valueQueue = (index < queues.size() ? queues[index]\r
- : queues.add (new ParamValueQueue()));\r
+ auto* valueQueue = (index < queues.size() ? queues[index]\r
+ : queues.add (new ParamValueQueue()));\r
\r
valueQueue->clear();\r
valueQueue->setParamID (id);\r
\r
void clearAllQueues() noexcept\r
{\r
+ const ScopedLock sl (queuesLock);\r
numQueuesUsed = 0;\r
}\r
\r
Steinberg::int32& sampleOffset,\r
Steinberg::Vst::ParamValue& value) override\r
{\r
- const ScopedLock sl (pointLock);\r
+ const ScopedLock sl (points.getLock());\r
\r
if (isPositiveAndBelow ((int) index, points.size()))\r
{\r
- ParamPoint e (points.getUnchecked ((int) index));\r
+ auto e = points.getUnchecked ((int) index);\r
sampleOffset = e.sampleOffset;\r
value = e.value;\r
+\r
return kResultTrue;\r
}\r
\r
sampleOffset = -1;\r
value = 0.0;\r
+\r
return kResultFalse;\r
}\r
\r
Steinberg::Vst::ParamValue value,\r
Steinberg::int32& index) override\r
{\r
- ParamPoint p = { sampleOffset, value };\r
-\r
- const ScopedLock sl (pointLock);\r
index = (Steinberg::int32) points.size();\r
- points.add (p);\r
+ points.add ({ sampleOffset, value });\r
return kResultTrue;\r
}\r
\r
- void clear() noexcept\r
- {\r
- const ScopedLock sl (pointLock);\r
- points.clearQuick();\r
- }\r
+ void clear() noexcept { points.clearQuick(); }\r
\r
private:\r
struct ParamPoint\r
\r
Atomic<int> refCount;\r
Vst::ParamID paramID = static_cast<Vst::ParamID> (-1);\r
- Array<ParamPoint> points;\r
- CriticalSection pointLock;\r
+ Array<ParamPoint, CriticalSection> points;\r
\r
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ParamValueQueue)\r
};\r
\r
Atomic<int> refCount;\r
+\r
OwnedArray<ParamValueQueue> queues;\r
int numQueuesUsed = 0;\r
+ CriticalSection queuesLock;\r
\r
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ParamValueQueueList)\r
};\r
\r
for (int i = 1; i < numUnits; ++i)\r
{\r
- Vst::UnitInfo ui = { 0 };\r
+ Vst::UnitInfo ui{};\r
unitInfo->getUnitInfo (i, ui);\r
infoMap[ui.id] = std::move (ui);\r
}\r
{\r
auto paramInfo = getParameterInfoForIndex (i);\r
auto* param = new VST3Parameter (*this,\r
+ i,\r
paramInfo.id,\r
(paramInfo.flags & Vst::ParameterInfo::kCanAutomate) != 0);\r
\r
bypassParam = param;\r
\r
std::function<AudioProcessorParameterGroup*(Vst::UnitID)> findOrCreateGroup;\r
-\r
findOrCreateGroup = [&groupMap, &infoMap, &findOrCreateGroup](Vst::UnitID groupID)\r
{\r
auto existingGroup = groupMap.find (groupID);\r
\r
Vst::ParameterInfo getParameterInfoForIndex (int index) const\r
{\r
- Vst::ParameterInfo paramInfo = { 0 };\r
+ Vst::ParameterInfo paramInfo{};\r
\r
if (processor != nullptr)\r
editController->getParameterInfo (index, paramInfo);\r
\r
Vst::ProgramListInfo getProgramListInfo (int index) const\r
{\r
- Vst::ProgramListInfo paramInfo = { 0 };\r
+ Vst::ProgramListInfo paramInfo{};\r
\r
if (unitInfo != nullptr)\r
unitInfo->getProgramListInfo (index, paramInfo);\r
return;\r
\r
Vst::UnitID programUnitID;\r
- Vst::ParameterInfo paramInfo = { 0 };\r
+ Vst::ParameterInfo paramInfo{};\r
\r
{\r
int idx, num = editController->getParameterCount();\r
\r
if (unitInfo != nullptr)\r
{\r
- Vst::UnitInfo uInfo = { 0 };\r
+ Vst::UnitInfo uInfo{};\r
const int unitCount = unitInfo->getUnitCount();\r
\r
for (int idx = 0; idx < unitCount; ++idx)\r
\r
for (int j = 0; j < programListCount; ++j)\r
{\r
- Vst::ProgramListInfo programListInfo = { 0 };\r
+ Vst::ProgramListInfo programListInfo{};\r
\r
if (unitInfo->getProgramListInfo (j, programListInfo) == kResultOk\r
&& programListInfo.id == uInfo.programListId)\r
PopupMenu::Options options;\r
\r
if (auto* ed = owner.getActiveEditor())\r
+ {\r
+ #if JUCE_WINDOWS && JUCE_WIN_PER_MONITOR_DPI_AWARE\r
+ if (auto* peer = ed->getPeer())\r
+ {\r
+ auto scale = peer->getPlatformScaleFactor();\r
+\r
+ x = roundToInt (x / scale);\r
+ y = roundToInt (y / scale);\r
+ }\r
+ #endif\r
+\r
options = options.withTargetScreenArea (ed->getScreenBounds().translated ((int) x, (int) y).withSize (1, 1));\r
+ }\r
\r
#if JUCE_MODAL_LOOPS_PERMITTED\r
// Unfortunately, Steinberg's docs explicitly say this should be modal..\r
desc.version = getVersion();\r
desc.numInputChannels = getTotalNumInputChannels();\r
desc.numOutputChannels = getTotalNumOutputChannels();\r
- desc.isInstrument = (vstEffect != nullptr && (vstEffect->flags & Vst2::effFlagsIsSynth) != 0);\r
+ desc.isInstrument = isSynthPlugin();\r
}\r
\r
bool initialiseEffect (double initialSampleRate, int initialBlockSize)\r
if (getVstCategory() != Vst2::kPlugCategShell) // (workaround for Waves 5 plugins which crash during this call)\r
updateStoredProgramNames();\r
\r
- wantsMidiMessages = pluginCanDo ("receiveVstMidiEvent") > 0;\r
+ wantsMidiMessages = pluginCanDo ("receiveVstMidiEvent") > 0 || isSynthPlugin();\r
\r
#if JUCE_MAC && JUCE_SUPPORT_CARBON\r
usesCocoaNSView = ((unsigned int) pluginCanDo ("hasCockosViewAsConfig") & 0xffff0000ul) == 0xbeef0000ul;\r
\r
Vst2::VstPlugCategory getVstCategory() const noexcept { return (Vst2::VstPlugCategory) dispatch (Vst2::effGetPlugCategory, 0, 0, nullptr, 0); }\r
\r
- int pluginCanDo (const char* text) const { return (int) dispatch (Vst2::effCanDo, 0, 0, (void*) text, 0); }\r
+ bool isSynthPlugin() const { return (vstEffect != nullptr && (vstEffect->flags & Vst2::effFlagsIsSynth) != 0); }\r
+\r
+ int pluginCanDo (const char* text) const { return (int) dispatch (Vst2::effCanDo, 0, 0, (void*) text, 0); }\r
\r
//==============================================================================\r
void prepareToPlay (double rate, int samplesPerBlockExpected) override\r
\r
if (initialised)\r
{\r
- wantsMidiMessages = wantsMidiMessages || (pluginCanDo ("receiveVstMidiEvent") > 0);\r
+ wantsMidiMessages = wantsMidiMessages || (pluginCanDo ("receiveVstMidiEvent") > 0) || isSynthPlugin();\r
\r
if (wantsMidiMessages)\r
midiEventsToSend.ensureSize (256);\r
//==============================================================================\r
String name;\r
CriticalSection lock;\r
- bool wantsMidiMessages = false, initialised = false, isPowerOn = false;\r
+ std::atomic<bool> wantsMidiMessages { false };\r
+ bool initialised = false, isPowerOn = false;\r
bool lastProcessBlockCallWasBypass = false, vstSupportsBypass = false;\r
mutable StringArray programNames;\r
AudioBuffer<float> outOfPlaceBuffer;\r
// Workaround: unfortunately old JUCE VST-2 plug-ins had a bug and would crash if\r
// you try to get the speaker arrangement when there are no input channels present.\r
// Hopefully, one day (when there are no more old JUCE plug-ins around), we can\r
- // commment out the next two lines.\r
+ // comment out the next two lines.\r
if (effect->numInputs == 0)\r
return false;\r
\r
if (auto* peer = getTopLevelComponent()->getPeer())\r
setScaleFactorAndDispatchMessage (peer->getPlatformScaleFactor());\r
\r
+ #if JUCE_LINUX\r
+ MessageManager::callAsync ([this] { componentMovedOrResized (true, true); });\r
+ #else\r
componentMovedOrResized (true, true);\r
+ #endif\r
}\r
\r
using ComponentMovementWatcher::componentVisibilityChanged;\r
==============================================================================\r
*/\r
\r
+\r
/*******************************************************************************\r
The block below describes the properties of this module, and is read by\r
the Projucer to automatically generate project code that uses it.\r
\r
BEGIN_JUCE_MODULE_DECLARATION\r
\r
- ID: juce_audio_processors\r
- vendor: juce\r
- version: 5.4.5\r
- name: JUCE audio processor classes\r
- description: Classes for loading and playing VST, AU, LADSPA, or internally-generated audio processors.\r
- website: http://www.juce.com/juce\r
- license: GPL/Commercial\r
-\r
- dependencies: juce_gui_extra, juce_audio_basics\r
- OSXFrameworks: CoreAudio CoreMIDI AudioToolbox\r
- iOSFrameworks: AudioToolbox\r
+ ID: juce_audio_processors\r
+ vendor: juce\r
+ version: 5.4.6\r
+ name: JUCE audio processor classes\r
+ description: Classes for loading and playing VST, AU, LADSPA, or internally-generated audio processors.\r
+ website: http://www.juce.com/juce\r
+ license: GPL/Commercial\r
+\r
+ dependencies: juce_gui_extra, juce_audio_basics\r
+ OSXFrameworks: CoreAudio CoreMIDI AudioToolbox\r
+ iOSFrameworks: AudioToolbox\r
\r
END_JUCE_MODULE_DECLARATION\r
\r
\r
AudioProcessor::~AudioProcessor()\r
{\r
- // ooh, nasty - the editor should have been deleted before its AudioProcessor.\r
- jassert (activeEditor == nullptr);\r
+ {\r
+ const ScopedLock sl (activeEditorLock);\r
+\r
+ // ooh, nasty - the editor should have been deleted before its AudioProcessor.\r
+ jassert (activeEditor == nullptr);\r
+ }\r
\r
#if JUCE_DEBUG && ! JUCE_DISABLE_AUDIOPROCESSOR_BEGIN_END_GESTURE_CHECKING\r
// This will fail if you've called beginParameterChangeGesture() for one\r
l->audioProcessorChanged (this);\r
}\r
\r
-#if JUCE_DEBUG\r
-void AudioProcessor::checkDuplicateParamIDs()\r
+void AudioProcessor::checkForDuplicateParamID (AudioProcessorParameter* param)\r
{\r
- duplicateParamIDCheck.reset();\r
-\r
- StringArray usedIDs;\r
- usedIDs.ensureStorageAllocated (flatParameterList.size());\r
-\r
- for (auto& p : flatParameterList)\r
- if (auto* withID = dynamic_cast<AudioProcessorParameterWithID*> (p))\r
- usedIDs.add (withID->paramID);\r
-\r
- usedIDs.sort (false);\r
-\r
- // This assertion checks whether you attempted to add two or more parameters with the same ID\r
- for (int i = 1; i < usedIDs.size(); ++i)\r
- jassert (usedIDs[i - 1] != usedIDs[i]);\r
-}\r
+ ignoreUnused (param);\r
\r
-struct AudioProcessor::DuplicateParamIDCheck : private AsyncUpdater\r
-{\r
- DuplicateParamIDCheck (AudioProcessor& p) : owner (p) { triggerAsyncUpdate(); }\r
- ~DuplicateParamIDCheck() override { cancelPendingUpdate(); }\r
-\r
- void handleAsyncUpdate() override { owner.checkDuplicateParamIDs(); }\r
-\r
- AudioProcessor& owner;\r
-};\r
-#endif\r
-\r
-void AudioProcessor::triggerDuplicateParamIDCheck()\r
-{\r
#if JUCE_DEBUG\r
- if (MessageManager::getInstanceWithoutCreating() != nullptr)\r
- duplicateParamIDCheck = std::make_unique<DuplicateParamIDCheck> (*this);\r
+ if (auto* withID = dynamic_cast<AudioProcessorParameterWithID*> (param))\r
+ {\r
+ auto insertResult = paramIDs.insert (withID->paramID);\r
+\r
+ // If you hit this assertion then the parameter ID is not unique\r
+ jassert (insertResult.second);\r
+ }\r
#endif\r
}\r
\r
param->parameterIndex = flatParameterList.size();\r
flatParameterList.add (param);\r
\r
- triggerDuplicateParamIDCheck();\r
+ checkForDuplicateParamID (param);\r
}\r
\r
void AudioProcessor::addParameterGroup (std::unique_ptr<AudioProcessorParameterGroup> group)\r
auto p = flatParameterList.getUnchecked (i);\r
p->processor = this;\r
p->parameterIndex = i;\r
+\r
+ checkForDuplicateParamID (p);\r
}\r
\r
parameterTree.addChild (std::move (group));\r
- triggerDuplicateParamIDCheck();\r
}\r
\r
void AudioProcessor::setParameterTree (AudioProcessorParameterGroup&& newTree)\r
{\r
+ #if JUCE_DEBUG\r
+ paramIDs.clear();\r
+ #endif\r
+\r
parameterTree = std::move (newTree);\r
flatParameterList = parameterTree.getParameters (true);\r
\r
auto p = flatParameterList.getUnchecked (i);\r
p->processor = this;\r
p->parameterIndex = i;\r
- }\r
\r
- triggerDuplicateParamIDCheck();\r
+ checkForDuplicateParamID (p);\r
+ }\r
}\r
\r
void AudioProcessor::refreshParameterList() {}\r
//==============================================================================\r
void AudioProcessor::editorBeingDeleted (AudioProcessorEditor* const editor) noexcept\r
{\r
- const ScopedLock sl (callbackLock);\r
+ const ScopedLock sl (activeEditorLock);\r
\r
if (activeEditor == editor)\r
activeEditor = nullptr;\r
}\r
\r
+AudioProcessorEditor* AudioProcessor::getActiveEditor() const noexcept\r
+{\r
+ const ScopedLock sl (activeEditorLock);\r
+ return activeEditor;\r
+}\r
+\r
AudioProcessorEditor* AudioProcessor::createEditorIfNeeded()\r
{\r
+ const ScopedLock sl (activeEditorLock);\r
+\r
if (activeEditor != nullptr)\r
return activeEditor;\r
\r
{\r
// you must give your editor comp a size before returning it..\r
jassert (ed->getWidth() > 0 && ed->getHeight() > 0);\r
-\r
- const ScopedLock sl (callbackLock);\r
activeEditor = ed;\r
}\r
\r
//==============================================================================\r
/** Constructor.\r
\r
- This constructor will create a main input and output bus which are diabled\r
+ This constructor will create a main input and output bus which are disabled\r
by default. If you need more fine-grained control then use the other constructors.\r
*/\r
AudioProcessor();\r
/** Return the number of channels of the current bus. */\r
inline int getNumberOfChannels() const noexcept { return cachedChannelCount; }\r
\r
- /** Set the number of channles of this bus. This will return false if the AudioProcessor\r
+ /** Set the number of channels of this bus. This will return false if the AudioProcessor\r
does not support this layout.\r
*/\r
bool setNumberOfChannels (int channels);\r
*/\r
int getChannelIndexInProcessBlockBuffer (bool isInput, int busIndex, int channelIndex) const noexcept;\r
\r
- /** Returns the offset in a bus's buffer from an absolute channel indes.\r
+ /** Returns the offset in a bus's buffer from an absolute channel index.\r
\r
This method returns the offset in a bus's buffer given an absolute channel index.\r
It also provides the bus index. For example, this method would return one\r
\r
/** Returns the next best layout which is contained in a channel layout map.\r
\r
- You can use this mehtod to help you implement getNextBestLayout. For example:\r
+ You can use this method to help you implement getNextBestLayout. For example:\r
\r
@code\r
BusesLayout getNextBestLayout (const BusesLayout& layouts) override\r
If this method returns a nullptr then you can still control the bypass by\r
calling processBlockBypassed instead of processBlock. On the other hand,\r
if this method returns a non-null value, you should never call\r
- processBlockBypassed but use the returned parameter to conrol the bypass\r
+ processBlockBypassed but use the returned parameter to control the bypass\r
state instead.\r
\r
A plug-in can override this function to return a parameter which control's your\r
virtual bool hasEditor() const = 0;\r
\r
//==============================================================================\r
- /** Returns the active editor, if there is one.\r
- Bear in mind this can return nullptr, even if an editor has previously been opened.\r
+ /** Returns the active editor, if there is one. Bear in mind this can return nullptr\r
+ even if an editor has previously been opened.\r
+\r
+ Note that you should only call this method from the message thread as the active\r
+ editor may be deleted by the message thread, causing a dangling pointer.\r
*/\r
- AudioProcessorEditor* getActiveEditor() const noexcept { return activeEditor; }\r
+ AudioProcessorEditor* getActiveEditor() const noexcept;\r
\r
/** Returns the active editor, or if there isn't one, it will create one.\r
This may call createEditor() internally to create the component.\r
/** Returns the group of parameters managed by this AudioProcessor. */\r
const AudioProcessorParameterGroup& getParameterTree() const;\r
\r
- /** Sets the group of parameters managed by this AudioProcessor. */\r
+ /** Sets the group of parameters managed by this AudioProcessor.\r
+\r
+ Replacing the tree after your AudioProcessor has been constructed will\r
+ crash many hosts, so don't do it! You may, however, change parameter and\r
+ group names by iterating the tree returned by getParameterTree().\r
+ Afterwards, call updateHostDisplay() to inform the host of the changes.\r
+ Not all hosts support dynamic changes to parameters and group names.\r
+ */\r
void setParameterTree (AudioProcessorParameterGroup&& newTree);\r
\r
/** A processor should implement this method so that the host can ask it to\r
rebuild its parameter tree.\r
- If a plugin never changes its parameters, it's enough to create its\r
- parameters in its constructor and do nothing in this method, but some\r
- may want to\r
+\r
+ For most plug-ins it's enough to simply add your parameters in the\r
+ constructor and leave this unimplemented.\r
*/\r
virtual void refreshParameterList();\r
\r
AudioProcessor about which track the AudioProcessor is loaded on. This method\r
may only be called on the message thread.\r
\r
- If you are implemeting an AudioProcessor then you can override this callback\r
+ If you are implementing an AudioProcessor then you can override this callback\r
to do something useful with the track properties such as changing the colour\r
of your AudioProcessor's editor. It's entirely up to the host when and how\r
often this callback will be called.\r
\r
//==============================================================================\r
/** @internal */\r
- AudioPlayHead* playHead = nullptr;\r
+ std::atomic<AudioPlayHead*> playHead { nullptr };\r
\r
/** @internal */\r
void sendParamChangeMessageToListeners (int parameterIndex, float newValue);\r
int blockSize = 0, latencySamples = 0;\r
bool suspended = false, nonRealtime = false;\r
ProcessingPrecision processingPrecision = singlePrecision;\r
- CriticalSection callbackLock, listenerLock;\r
+ CriticalSection callbackLock, listenerLock, activeEditorLock;\r
\r
friend class Bus;\r
mutable OwnedArray<Bus> inputBuses, outputBuses;\r
#endif\r
\r
bool textRecursionCheck = false;\r
-\r
- struct DuplicateParamIDCheck;\r
- std::unique_ptr<DuplicateParamIDCheck> duplicateParamIDCheck;\r
- void checkDuplicateParamIDs();\r
+ std::unordered_set<String> paramIDs;\r
#endif\r
\r
+ void checkForDuplicateParamID (AudioProcessorParameter*);\r
+\r
AudioProcessorListener* getListenerLocked (int) const noexcept;\r
void updateSpeakerFormatStrings();\r
void audioIOChanged (bool busNumberChanged, bool channelNumChanged);\r
void getNextBestLayout (const BusesLayout&, BusesLayout&) const;\r
- void triggerDuplicateParamIDCheck();\r
\r
template <typename floatType>\r
void processBypassed (AudioBuffer<floatType>&, MidiBuffer&);\r
if (shouldHaveCornerResizer != (resizableCorner != nullptr))\r
{\r
if (shouldHaveCornerResizer)\r
- {\r
- resizableCorner.reset (new ResizableCornerComponent (this, constrainer));\r
- Component::addChildComponent (resizableCorner.get());\r
- resizableCorner->setAlwaysOnTop (true);\r
- }\r
+ attachResizableCornerComponent();\r
else\r
- {\r
resizableCorner.reset();\r
- }\r
}\r
}\r
\r
|| newConstrainer->getMinimumHeight() != newConstrainer->getMaximumHeight());\r
\r
attachConstrainer (newConstrainer);\r
+\r
+ if (resizableCorner != nullptr)\r
+ attachResizableCornerComponent();\r
}\r
}\r
\r
}\r
}\r
\r
+void AudioProcessorEditor::attachResizableCornerComponent()\r
+{\r
+ resizableCorner.reset (new ResizableCornerComponent (this, constrainer));\r
+ Component::addChildComponent (resizableCorner.get());\r
+ resizableCorner->setAlwaysOnTop (true);\r
+ editorResized (true);\r
+}\r
+\r
void AudioProcessorEditor::setBoundsConstrained (Rectangle<int> newBounds)\r
{\r
if (constrainer != nullptr)\r
void editorResized (bool wasResized);\r
void updatePeer();\r
void attachConstrainer (ComponentBoundsConstrainer*);\r
+ void attachResizableCornerComponent();\r
\r
//==============================================================================\r
std::unique_ptr<AudioProcessorEditorListener> resizeListener;\r
tempBufferDouble.makeCopyOf (buffer, true);\r
\r
if (node->isBypassed())\r
- processor.processBlockBypassed (tempBufferDouble, midiMessages);\r
+ node->processBlockBypassed (tempBufferDouble, midiMessages);\r
else\r
- processor.processBlock (tempBufferDouble, midiMessages);\r
+ node->processBlock (tempBufferDouble, midiMessages);\r
\r
buffer.makeCopyOf (tempBufferDouble, true);\r
}\r
else\r
{\r
if (node->isBypassed())\r
- processor.processBlockBypassed (buffer, midiMessages);\r
+ node->processBlockBypassed (buffer, midiMessages);\r
else\r
- processor.processBlock (buffer, midiMessages);\r
+ node->processBlock (buffer, midiMessages);\r
}\r
}\r
\r
if (processor.isUsingDoublePrecision())\r
{\r
if (node->isBypassed())\r
- processor.processBlockBypassed (buffer, midiMessages);\r
+ node->processBlockBypassed (buffer, midiMessages);\r
else\r
- processor.processBlock (buffer, midiMessages);\r
+ node->processBlock (buffer, midiMessages);\r
}\r
else\r
{\r
tempBufferFloat.makeCopyOf (buffer, true);\r
\r
if (node->isBypassed())\r
- processor.processBlockBypassed (tempBufferFloat, midiMessages);\r
+ node->processBlockBypassed (tempBufferFloat, midiMessages);\r
else\r
- processor.processBlock (tempBufferFloat, midiMessages);\r
+ node->processBlock (tempBufferFloat, midiMessages);\r
\r
buffer.makeCopyOf (tempBufferFloat, true);\r
}\r
void AudioProcessorGraph::Node::prepare (double newSampleRate, int newBlockSize,\r
AudioProcessorGraph* graph, ProcessingPrecision precision)\r
{\r
+ const ScopedLock lock (processorLock);\r
+\r
if (! isPrepared)\r
{\r
- isPrepared = true;\r
setParentGraph (graph);\r
\r
// try to align the precision of the processor and the graph\r
\r
processor->setRateAndBufferSizeDetails (newSampleRate, newBlockSize);\r
processor->prepareToPlay (newSampleRate, newBlockSize);\r
+\r
+ // This may be checked from other threads that haven't taken the processorLock,\r
+ // so we need to leave it until the processor has been completely prepared\r
+ isPrepared = true;\r
}\r
}\r
\r
void AudioProcessorGraph::Node::unprepare()\r
{\r
+ const ScopedLock lock (processorLock);\r
+\r
if (isPrepared)\r
{\r
isPrepared = false;\r
\r
void AudioProcessorGraph::Node::setParentGraph (AudioProcessorGraph* const graph) const\r
{\r
+ const ScopedLock lock (processorLock);\r
+\r
if (auto* ioProc = dynamic_cast<AudioProcessorGraph::AudioGraphIOProcessor*> (processor.get()))\r
ioProc->setParentGraph (graph);\r
}\r
\r
AudioProcessorGraph::~AudioProcessorGraph()\r
{\r
+ cancelPendingUpdate();\r
clearRenderingSequence();\r
clear();\r
}\r
{\r
sendChangeMessage();\r
\r
- if (isPrepared.get() != 0)\r
+ if (isPrepared)\r
triggerAsyncUpdate();\r
}\r
\r
newProcessor->setPlayHead (getPlayHead());\r
\r
Node::Ptr n (new Node (nodeID, std::move (newProcessor)));\r
- nodes.add (n.get());\r
+\r
+ {\r
+ const ScopedLock sl (getCallbackLock());\r
+ nodes.add (n.get());\r
+ }\r
+\r
n->setParentGraph (this);\r
topologyChanged();\r
return n;\r
\r
bool AudioProcessorGraph::removeNode (NodeID nodeId)\r
{\r
+ const ScopedLock sl (getCallbackLock());\r
+\r
for (int i = nodes.size(); --i >= 0;)\r
{\r
if (nodes.getUnchecked(i)->nodeID == nodeId)\r
\r
void AudioProcessorGraph::buildRenderingSequence()\r
{\r
- std::unique_ptr<RenderSequenceFloat> newSequenceF (new RenderSequenceFloat());\r
- std::unique_ptr<RenderSequenceDouble> newSequenceD (new RenderSequenceDouble());\r
+ auto newSequenceF = std::make_unique<RenderSequenceFloat>();\r
+ auto newSequenceD = std::make_unique<RenderSequenceDouble>();\r
\r
- {\r
- MessageManagerLock mml;\r
+ RenderSequenceBuilder<RenderSequenceFloat> builderF (*this, *newSequenceF);\r
+ RenderSequenceBuilder<RenderSequenceDouble> builderD (*this, *newSequenceD);\r
\r
- RenderSequenceBuilder<RenderSequenceFloat> builderF (*this, *newSequenceF);\r
- RenderSequenceBuilder<RenderSequenceDouble> builderD (*this, *newSequenceD);\r
- }\r
+ const ScopedLock sl (getCallbackLock());\r
\r
- {\r
- const ScopedLock sl (getCallbackLock());\r
- newSequenceF->prepareBuffers (getBlockSize());\r
- newSequenceD->prepareBuffers (getBlockSize());\r
- }\r
+ const auto currentBlockSize = getBlockSize();\r
+ newSequenceF->prepareBuffers (currentBlockSize);\r
+ newSequenceD->prepareBuffers (currentBlockSize);\r
\r
if (anyNodesNeedPreparing())\r
{\r
- {\r
- const ScopedLock sl (getCallbackLock());\r
- renderSequenceFloat.reset();\r
- renderSequenceDouble.reset();\r
- }\r
+ renderSequenceFloat.reset();\r
+ renderSequenceDouble.reset();\r
\r
for (auto* node : nodes)\r
- node->prepare (getSampleRate(), getBlockSize(), this, getProcessingPrecision());\r
+ node->prepare (getSampleRate(), currentBlockSize, this, getProcessingPrecision());\r
}\r
\r
- const ScopedLock sl (getCallbackLock());\r
+ isPrepared = 1;\r
\r
- std::swap (renderSequenceFloat, newSequenceF);\r
+ std::swap (renderSequenceFloat, newSequenceF);\r
std::swap (renderSequenceDouble, newSequenceD);\r
}\r
\r
void AudioProcessorGraph::handleAsyncUpdate()\r
{\r
buildRenderingSequence();\r
- isPrepared = 1;\r
}\r
\r
//==============================================================================\r
void AudioProcessorGraph::prepareToPlay (double sampleRate, int estimatedSamplesPerBlock)\r
{\r
- setRateAndBufferSizeDetails (sampleRate, estimatedSamplesPerBlock);\r
+ {\r
+ const ScopedLock sl (getCallbackLock());\r
+ setRateAndBufferSizeDetails (sampleRate, estimatedSamplesPerBlock);\r
+ }\r
+\r
clearRenderingSequence();\r
\r
if (MessageManager::getInstance()->isThisTheMessageThread())\r
{\r
const ScopedLock sl (getCallbackLock());\r
\r
+ cancelPendingUpdate();\r
+\r
isPrepared = 0;\r
\r
for (auto* n : nodes)\r
static void processBlockForBuffer (AudioBuffer<FloatType>& buffer, MidiBuffer& midiMessages,\r
AudioProcessorGraph& graph,\r
std::unique_ptr<SequenceType>& renderSequence,\r
- Atomic<int>& isPrepared)\r
+ std::atomic<bool>& isPrepared)\r
{\r
if (graph.isNonRealtime())\r
{\r
- while (isPrepared.get() == 0)\r
+ while (! isPrepared)\r
Thread::sleep (1);\r
\r
const ScopedLock sl (graph.getCallbackLock());\r
{\r
const ScopedLock sl (graph.getCallbackLock());\r
\r
- if (isPrepared.get() == 1)\r
+ if (isPrepared)\r
{\r
if (renderSequence != nullptr)\r
renderSequence->perform (buffer, midiMessages, graph.getPlayHead());\r
\r
void AudioProcessorGraph::processBlock (AudioBuffer<float>& buffer, MidiBuffer& midiMessages)\r
{\r
- if (isPrepared.get() == 0 && MessageManager::getInstance()->isThisTheMessageThread())\r
+ if ((! isPrepared) && MessageManager::getInstance()->isThisTheMessageThread())\r
handleAsyncUpdate();\r
\r
processBlockForBuffer<float> (buffer, midiMessages, *this, renderSequenceFloat, isPrepared);\r
\r
void AudioProcessorGraph::processBlock (AudioBuffer<double>& buffer, MidiBuffer& midiMessages)\r
{\r
- if (isPrepared.get() == 0 && MessageManager::getInstance()->isThisTheMessageThread())\r
+ if ((! isPrepared) && MessageManager::getInstance()->isThisTheMessageThread())\r
handleAsyncUpdate();\r
\r
processBlockForBuffer<double> (buffer, midiMessages, *this, renderSequenceDouble, isPrepared);\r
private:\r
//==============================================================================\r
friend class AudioProcessorGraph;\r
+ template <typename Float>\r
+ friend struct GraphRenderSequence;\r
\r
struct Connection\r
{\r
\r
const std::unique_ptr<AudioProcessor> processor;\r
Array<Connection> inputs, outputs;\r
- bool isPrepared = false, bypassed = false;\r
+ bool isPrepared = false;\r
+ std::atomic<bool> bypassed { false };\r
\r
Node (NodeID, std::unique_ptr<AudioProcessor>) noexcept;\r
\r
void prepare (double newSampleRate, int newBlockSize, AudioProcessorGraph*, ProcessingPrecision);\r
void unprepare();\r
\r
+ template <typename Sample>\r
+ void processBlock (AudioBuffer<Sample>& audio, MidiBuffer& midi)\r
+ {\r
+ const ScopedLock lock (processorLock);\r
+ processor->processBlock (audio, midi);\r
+ }\r
+\r
+ template <typename Sample>\r
+ void processBlockBypassed (AudioBuffer<Sample>& audio, MidiBuffer& midi)\r
+ {\r
+ const ScopedLock lock (processorLock);\r
+ processor->processBlockBypassed (audio, midi);\r
+ }\r
+\r
+ CriticalSection processorLock;\r
+\r
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Node)\r
};\r
\r
added a processor to the graph, the graph owns it and will delete it later when\r
it is no longer needed.\r
\r
- The optional nodeId parameter lets you specify an ID to use for the node, but\r
- if the value is already in use, this new node will overwrite the old one.\r
+ The optional nodeId parameter lets you specify a unique ID to use for the node.\r
+ If the value is already in use, this method will fail and return an empty node.\r
\r
If this succeeds, it returns a pointer to the newly-created node.\r
*/\r
\r
friend class AudioGraphIOProcessor;\r
\r
- Atomic<int> isPrepared { 0 };\r
+ std::atomic<bool> isPrepared { false };\r
\r
void topologyChanged();\r
void handleAsyncUpdate() override;\r
/** Returns the current value of the parameter as a String.\r
\r
This function can be called when you are hosting plug-ins to get a\r
- more specialsed textual represenation of the current value from the\r
+ more specialised textual representation of the current value from the\r
plug-in, for example "On" rather than "1.0".\r
\r
If you are implementing a plug-in then you should ignore this function\r
String AudioProcessorParameterGroup::getSeparator() const { return separator; }\r
const AudioProcessorParameterGroup* AudioProcessorParameterGroup::getParent() const noexcept { return parent; }\r
\r
+void AudioProcessorParameterGroup::setName (String newName) { name = std::move (newName); }\r
+\r
const AudioProcessorParameterGroup::AudioProcessorParameterNode* const* AudioProcessorParameterGroup::begin() const noexcept { return const_cast<const AudioProcessorParameterNode**> (children.begin()); }\r
const AudioProcessorParameterGroup::AudioProcessorParameterNode* const* AudioProcessorParameterGroup::end() const noexcept { return const_cast<const AudioProcessorParameterNode**> (children.end()); }\r
\r
addChild (std::forward<Args> (remainingChildren)...);\r
}\r
\r
+ /** Once a group has been added to an AudioProcessor don't try to mutate it by\r
+ moving or swapping it - this will crash most hosts.\r
+ */\r
AudioProcessorParameterGroup (AudioProcessorParameterGroup&&);\r
+\r
+ /** Once a group has been added to an AudioProcessor don't try to mutate it by\r
+ moving or swapping it - this will crash most hosts.\r
+ */\r
AudioProcessorParameterGroup& operator= (AudioProcessorParameterGroup&&);\r
\r
+ /** Destructor. */\r
~AudioProcessorParameterGroup();\r
\r
//==============================================================================\r
/** Returns the group's separator string. */\r
String getSeparator() const;\r
\r
- /** Returns the parent of the group, or nullptr if this is a top-levle group. */\r
+ /** Returns the parent of the group, or nullptr if this is a top-level group. */\r
const AudioProcessorParameterGroup* getParent() const noexcept;\r
\r
+ //==============================================================================\r
+ /** Changes the name of the group. If you do this after the group has been added\r
+ to an AudioProcessor, call updateHostDisplay() to inform the host of the\r
+ change. Not all hosts support dynamic group name changes.\r
+ */\r
+ void setName (String newName);\r
+\r
//==============================================================================\r
const AudioProcessorParameterNode* const* begin() const noexcept;\r
const AudioProcessorParameterNode* const* end() const noexcept;\r
Array<const AudioProcessorParameterGroup*> getGroupsForParameter (AudioProcessorParameter*) const;\r
\r
//==============================================================================\r
- /** Adds a child to the group. */\r
+ /** Adds a child to the group.\r
+\r
+ Do not add children to a group which has itself already been added to the\r
+ AudioProcessor - the new elements will be ignored.\r
+ */\r
template <typename ParameterOrGroup>\r
void addChild (std::unique_ptr<ParameterOrGroup> child)\r
{\r
append (std::move (child));\r
}\r
\r
- /** Adds multiple parameters or sub-groups to this group. */\r
+ /** Adds multiple parameters or sub-groups to this group.\r
+\r
+ Do not add children to a group which has itself already been added to the\r
+ AudioProcessor - the new elements will be ignored.\r
+ */\r
template <typename ParameterOrGroup, typename... Args>\r
void addChild (std::unique_ptr<ParameterOrGroup> firstChild, Args&&... remainingChildren)\r
{\r
}\r
\r
#ifndef DOXYGEN\r
- // This class now has a move operator, so if you're try to move them around, you should\r
- // use that, or if you really need to swap two groups, just call std::swap\r
+ // This class now has a move operator, so if you're trying to move them around, you\r
+ // should use that, or if you really need to swap two groups, just call std::swap.\r
+ // However, remember that swapping a group that's already owned by an AudioProcessor\r
+ // will most likely crash the host, so don't do that.\r
JUCE_DEPRECATED_WITH_BODY (void swapWith (AudioProcessorParameterGroup& other), { std::swap (*this, other); })\r
#endif\r
\r
height += comp->getHeight();\r
}\r
\r
- setSize (maxWidth, jmax (height, 100));\r
+ setSize (maxWidth, jmax (height, 125));\r
}\r
\r
~ParametersPanel() override\r
// You need to use at least one thread when scanning plug-ins asynchronously\r
jassert (! allowAsync || (numThreads > 0));\r
\r
- // If the filesOrIdentifiersToScan argumnent isn't empty, we should only scan these\r
+ // If the filesOrIdentifiersToScan argument isn't empty, we should only scan these\r
// If the path is empty, then paths aren't used for this format.\r
if (filesOrIdentifiersToScan.isEmpty() && path.getNumPaths() > 0)\r
{\r
}\r
}\r
\r
-AudioParameterBool::~AudioParameterBool() {}\r
+AudioParameterBool::~AudioParameterBool()\r
+{\r
+ #if __cpp_lib_atomic_is_always_lock_free\r
+ static_assert (std::atomic<float>::is_always_lock_free,\r
+ "AudioParameterBool requires a lock-free std::atomic<float>");\r
+ #endif\r
+}\r
\r
float AudioParameterBool::getValue() const { return value; }\r
void AudioParameterBool::setValue (float newValue) { value = newValue; valueChanged (get()); }\r
float getValueForText (const String&) const override;\r
\r
const NormalisableRange<float> range { 0.0f, 1.0f, 1.0f };\r
- float value;\r
+ std::atomic<float> value;\r
const float defaultValue;\r
std::function<String(bool, int)> stringFromBoolFunction;\r
std::function<bool(const String&)> boolFromStringFunction;\r
indexFromStringFunction = [this] (const String& text) { return choices.indexOf (text); };\r
}\r
\r
-AudioParameterChoice::~AudioParameterChoice() {}\r
+AudioParameterChoice::~AudioParameterChoice()\r
+{\r
+ #if __cpp_lib_atomic_is_always_lock_free\r
+ static_assert (std::atomic<float>::is_always_lock_free,\r
+ "AudioParameterChoice requires a lock-free std::atomic<float>");\r
+ #endif\r
+}\r
\r
float AudioParameterChoice::getValue() const { return convertTo0to1 (value); }\r
void AudioParameterChoice::setValue (float newValue) { value = convertFrom0to1 (newValue); valueChanged (getIndex()); }\r
~AudioParameterChoice() override;\r
\r
/** Returns the current index of the selected item. */\r
- int getIndex() const noexcept { return roundToInt (value); }\r
+ int getIndex() const noexcept { return roundToInt (value.load()); }\r
\r
/** Returns the current index of the selected item. */\r
operator int() const noexcept { return getIndex(); }\r
float getValueForText (const String&) const override;\r
\r
const NormalisableRange<float> range;\r
- float value;\r
+ std::atomic<float> value;\r
const float defaultValue;\r
std::function<String(int, int)> stringFromIndexFunction;\r
std::function<int(const String&)> indexFromStringFunction;\r
{\r
}\r
\r
-AudioParameterFloat::~AudioParameterFloat() {}\r
+AudioParameterFloat::~AudioParameterFloat()\r
+{\r
+ #if __cpp_lib_atomic_is_always_lock_free\r
+ static_assert (std::atomic<float>::is_always_lock_free,\r
+ "AudioParameterFloat requires a lock-free std::atomic<float>");\r
+ #endif\r
+}\r
\r
float AudioParameterFloat::getValue() const { return convertTo0to1 (value); }\r
void AudioParameterFloat::setValue (float newValue) { value = convertFrom0to1 (newValue); valueChanged (get()); }\r
String getText (float, int) const override;\r
float getValueForText (const String&) const override;\r
\r
- float value;\r
+ std::atomic<float> value;\r
const float defaultValue;\r
std::function<String(float, int)> stringFromValueFunction;\r
std::function<float(const String&)> valueFromStringFunction;\r
intFromStringFunction = [] (const String& text) { return text.getIntValue(); };\r
}\r
\r
-AudioParameterInt::~AudioParameterInt() {}\r
+AudioParameterInt::~AudioParameterInt()\r
+{\r
+ #if __cpp_lib_atomic_is_always_lock_free\r
+ static_assert (std::atomic<float>::is_always_lock_free,\r
+ "AudioParameterInt requires a lock-free std::atomic<float>");\r
+ #endif\r
+}\r
\r
float AudioParameterInt::getValue() const { return convertTo0to1 (value); }\r
void AudioParameterInt::setValue (float newValue) { value = convertFrom0to1 (newValue); valueChanged (get()); }\r
~AudioParameterInt() override;\r
\r
/** Returns the parameter's current value as an integer. */\r
- int get() const noexcept { return roundToInt (value); }\r
+ int get() const noexcept { return roundToInt (value.load()); }\r
\r
/** Returns the parameter's current value as an integer. */\r
operator int() const noexcept { return get(); }\r
float getValueForText (const String&) const override;\r
\r
const NormalisableRange<float> range;\r
- float value;\r
+ std::atomic<float> value;\r
const float defaultValue;\r
std::function<String(int, int)> stringFromIntFunction;\r
std::function<int(const String&)> intFromStringFunction;\r
return parameter.getText (normalise (value), 0);\r
}\r
\r
- float getDenormalisedValue() const { return unnormalisedValue; }\r
- float& getRawDenormalisedValue() { return unnormalisedValue; }\r
+ float getDenormalisedValue() const { return unnormalisedValue; }\r
+ std::atomic<float>& getRawDenormalisedValue() { return unnormalisedValue; }\r
\r
bool flushToTree (const Identifier& key, UndoManager* um)\r
{\r
if ((float) *valueProperty != unnormalisedValue)\r
{\r
ScopedValueSetter<bool> svs (ignoreParameterChangedCallbacks, true);\r
- tree.setProperty (key, unnormalisedValue, um);\r
+ tree.setProperty (key, unnormalisedValue.load(), um);\r
}\r
}\r
else\r
{\r
- tree.setProperty (key, unnormalisedValue, nullptr);\r
+ tree.setProperty (key, unnormalisedValue.load(), nullptr);\r
}\r
\r
return true;\r
\r
RangedAudioParameter& parameter;\r
ListenerList<Listener> listeners;\r
- float unnormalisedValue{};\r
+ std::atomic<float> unnormalisedValue{};\r
std::atomic<bool> needsUpdate { true };\r
bool listenersNeedCalling { true }, ignoreParameterChangedCallbacks { false };\r
};\r
state.addListener (this);\r
}\r
\r
-AudioProcessorValueTreeState::~AudioProcessorValueTreeState() {}\r
+AudioProcessorValueTreeState::~AudioProcessorValueTreeState()\r
+{\r
+ stopTimer();\r
+}\r
\r
//==============================================================================\r
RangedAudioParameter* AudioProcessorValueTreeState::createAndAddParameter (const String& paramID,\r
return nullptr;\r
}\r
\r
-float* AudioProcessorValueTreeState::getRawParameterValue (StringRef paramID) const noexcept\r
+std::atomic<float>* AudioProcessorValueTreeState::getRawParameterValue (StringRef paramID) const noexcept\r
{\r
if (auto* p = getParameterAdapter (paramID))\r
return &p->getRawDenormalisedValue();\r
adapter.setDenormalisedValue (value);\r
\r
expectEquals (adapter.getDenormalisedValue(), value);\r
- expectEquals (adapter.getRawDenormalisedValue(), value);\r
+ expectEquals (adapter.getRawDenormalisedValue().load(), value);\r
};\r
\r
test ({ -20, -10 }, -15);\r
const auto value = 0.5f;\r
param->setValueNotifyingHost (value);\r
\r
- expectEquals (*proc.state.getRawParameterValue (key), value);\r
+ expectEquals (proc.state.getRawParameterValue (key)->load(), value);\r
}\r
\r
beginTest ("After adding an APVTS::Parameter, its value is the default value");\r
nullptr,\r
nullptr));\r
\r
- expectEquals (*proc.state.getRawParameterValue (key), value);\r
+ expectEquals (proc.state.getRawParameterValue (key)->load(), value);\r
}\r
\r
beginTest ("Listeners receive notifications when parameters change");\r
value = newValue;\r
\r
expectEquals (param->getValue(), newValue);\r
- expectEquals (*proc.state.getRawParameterValue (key), newValue);\r
+ expectEquals (proc.state.getRawParameterValue (key)->load(), newValue);\r
}\r
\r
beginTest ("When the parameter value is changed, custom parameter values are updated");\r
value = newValue;\r
\r
expectEquals (paramPtr->getCurrentChoiceName(), choices[int (newValue)]);\r
- expectEquals (*proc.state.getRawParameterValue (key), newValue);\r
+ expectEquals (proc.state.getRawParameterValue (key)->load(), newValue);\r
}\r
\r
beginTest ("When the parameter value is changed, listeners are notified");\r
Note that calling this method from within AudioProcessorValueTreeState::Listener::parameterChanged()\r
is not guaranteed to return an up-to-date value for the parameter.\r
*/\r
- float* getRawParameterValue (StringRef parameterID) const noexcept;\r
+ std::atomic<float>* getRawParameterValue (StringRef parameterID) const noexcept;\r
\r
//==============================================================================\r
/** A listener class that can be attached to an AudioProcessorValueTreeState.\r
\r
An AudioSource has two states: prepared and unprepared.\r
\r
- The prepareToPlay() method is guaranteed to be called at least once on an 'unpreprared'\r
+ The prepareToPlay() method is guaranteed to be called at least once on an 'unprepared'\r
source to put it into a 'prepared' state before any calls will be made to getNextAudioBlock().\r
This callback allows the source to initialise any resources it might need when playing.\r
\r
==============================================================================\r
*/\r
\r
+\r
/*******************************************************************************\r
The block below describes the properties of this module, and is read by\r
the Projucer to automatically generate project code that uses it.\r
\r
BEGIN_JUCE_MODULE_DECLARATION\r
\r
- ID: juce_audio_utils\r
- vendor: juce\r
- version: 5.4.5\r
- name: JUCE extra audio utility classes\r
- description: Classes for audio-related GUI and miscellaneous tasks.\r
- website: http://www.juce.com/juce\r
- license: GPL/Commercial\r
-\r
- dependencies: juce_gui_extra, juce_audio_processors, juce_audio_formats, juce_audio_devices\r
- OSXFrameworks: CoreAudioKit DiscRecording\r
- iOSFrameworks: CoreAudioKit\r
+ ID: juce_audio_utils\r
+ vendor: juce\r
+ version: 5.4.6\r
+ name: JUCE extra audio utility classes\r
+ description: Classes for audio-related GUI and miscellaneous tasks.\r
+ website: http://www.juce.com/juce\r
+ license: GPL/Commercial\r
+\r
+ dependencies: juce_gui_extra, juce_audio_processors, juce_audio_formats, juce_audio_devices\r
+ OSXFrameworks: CoreAudioKit DiscRecording\r
+ iOSFrameworks: CoreAudioKit\r
\r
END_JUCE_MODULE_DECLARATION\r
\r
loopBlock, /**< Loop control block type. */\r
developerControlBlock, /**< Developer control block type. */\r
touchBlock, /**< Touch control block type. */\r
- seaboardBlock /**< Seaboard block type. */\r
+ seaboardBlock, /**< Seaboard block type. */\r
+ lumiKeysBlock /**< LUMI Keys block type */\r
};\r
\r
/** The Block class is reference-counted, so always use a Block::Ptr when\r
/** Provides a callback that will be called when a config changes. */\r
virtual void setConfigChangedCallback (std::function<void(Block&, const ConfigMetaData&, uint32)>) = 0;\r
\r
- /** Provides a callback that will be called when a prgoram has been loaded. */\r
+ /** Provides a callback that will be called when a program has been loaded. */\r
virtual void setProgramLoadedCallback (std::function<void(Block&)> programLoaded) = 0;\r
\r
//==============================================================================\r
*/\r
struct BlockConfigManager\r
{\r
- void setDeviceIndex (TopologyIndex newDeviceIndex) { deviceIndex = newDeviceIndex; }\r
- void setDeviceComms (PhysicalTopologySource::DeviceConnection* newConn) { deviceConnection = newConn; }\r
-\r
- static constexpr uint32 numConfigItems = 69;\r
-\r
/** Structure describing a configuration */\r
struct ConfigDescription\r
{\r
}\r
};\r
\r
+ BlockConfigManager (Array<ConfigDescription> defaultConfig)\r
+ {\r
+ for (auto c : defaultConfig)\r
+ {\r
+ uint32 itemIndex;\r
+\r
+ if (getIndexForItem (c.item, itemIndex))\r
+ configList[itemIndex] = c;\r
+ }\r
+ }\r
+\r
+ void setDeviceIndex (TopologyIndex newDeviceIndex) { deviceIndex = newDeviceIndex; }\r
+ void setDeviceComms (PhysicalTopologySource::DeviceConnection* newConn) { deviceConnection = newConn; }\r
+\r
+ static constexpr uint32 numConfigItems = 69;\r
+\r
+ static constexpr const char* midiSettingsGroup = "MIDI Settings";\r
+ static constexpr const char* pitchGroup = "Pitch";\r
+ static constexpr const char* playGroup = "Play mode";\r
+ static constexpr const char* sensitivityGroup = "Sensitivity";\r
+ static constexpr const char* rhythmGroup = "Rhythm";\r
+ static constexpr const char* coloursGroup = "Colors";\r
+\r
ConfigDescription configList[numConfigItems] =\r
{\r
- { midiStartChannel, 2, 1, 16, false, "MIDI Start Channel", ConfigType::integer, {}, "MIDI Settings" },\r
- { midiEndChannel, 16, 1, 16, false, "MIDI End Channel", ConfigType::integer, {}, "MIDI Settings" },\r
- { midiUseMPE, 1, 0, 2, false, "MIDI Mode", ConfigType::options, { "Multi Channel",\r
+ { midiStartChannel, 2, 1, 16, false, "MIDI Start Channel", ConfigType::integer, {}, midiSettingsGroup },\r
+ { midiEndChannel, 16, 1, 16, false, "MIDI End Channel", ConfigType::integer, {}, midiSettingsGroup },\r
+ { midiUseMPE, 1, 0, 2, false, "MIDI Mode", ConfigType::options, { "Multi Channel",\r
"MPE",\r
- "Single Channel" }, "MIDI Settings" },\r
- { pitchBendRange, 48, 1, 96, false, "Pitch Bend Range", ConfigType::integer, {}, "MIDI Settings" },\r
- { midiChannelRange, 15, 1, 15, false, "No. MIDI Channels", ConfigType::integer, {}, "MIDI Settings" },\r
- { MPEZone, 0, 0, 1, false, "MPE Zone", ConfigType::options, { "Lower Zone",\r
- "Upper Zone"}, "MIDI Settings" },\r
- { octave, 0, -4, 6, false, "Octave", ConfigType::integer, {}, "Pitch" },\r
- { transpose, 0, -11, 11, false, "Transpose", ConfigType::integer, {}, "Pitch" },\r
- { slideCC, 74, 0, 127, false, "Slide CC", ConfigType::integer, {}, "Play mode" },\r
- { slideMode, 0, 0, 2, false, "Slide Mode", ConfigType::options, { "Absolute",\r
+ "Single Channel" }, midiSettingsGroup },\r
+ { pitchBendRange, 48, 1, 96, false, "Pitch Bend Range", ConfigType::integer, {}, midiSettingsGroup },\r
+ { midiChannelRange, 15, 1, 15, false, "No. MIDI Channels", ConfigType::integer, {}, midiSettingsGroup },\r
+ { MPEZone, 0, 0, 1, false, "MPE Zone", ConfigType::options, { "Lower Zone",\r
+ "Upper Zone"}, midiSettingsGroup },\r
+ { octave, 0, -4, 6, false, "Octave", ConfigType::integer, {}, pitchGroup },\r
+ { transpose, 0, -11, 11, false, "Transpose", ConfigType::integer, {}, pitchGroup },\r
+ { slideCC, 74, 0, 127, false, "Slide CC", ConfigType::integer, {}, playGroup },\r
+ { slideMode, 0, 0, 2, false, "Slide Mode", ConfigType::options, { "Absolute",\r
"Relative Unipolar",\r
- "Relative Bipolar" }, "Play mode" },\r
- { velocitySensitivity, 100, 0, 127, false, "Strike Sensitivity", ConfigType::integer, {}, "5D Touch" },\r
- { glideSensitivity, 100, 0, 127, false, "Glide Sensitivity", ConfigType::integer, {}, "5D Touch" },\r
- { slideSensitivity, 100, 0, 127, false, "Slide Sensitivity", ConfigType::integer, {}, "5D Touch" },\r
- { pressureSensitivity, 100, 0, 127, false, "Pressure Sensitivity", ConfigType::integer, {}, "5D Touch" },\r
- { liftSensitivity, 100, 0, 127, false, "Lift Sensitivity", ConfigType::integer, {}, "5D Touch" },\r
- { fixedVelocity, 0, 0, 1, false, "Fixed Velocity", ConfigType::boolean, {}, "5D Touch" },\r
- { fixedVelocityValue, 127, 1, 127, false, "Fixed Velocity Value", ConfigType::integer, {}, "5D Touch" },\r
- { pianoMode, 0, 0, 1, false, "Piano Mode", ConfigType::boolean, {}, "Play mode" },\r
- { glideLock, 0, 0, 127, false, "Glide Rate", ConfigType::integer, {}, "Play mode" },\r
- { glideLockEnable, 0, 0, 1, false, "Glide Lock Enable", ConfigType::boolean, {}, "Play mode" },\r
- { mode, 4, 1, 5, false, "Mode", ConfigType::integer, {}, "Play mode" },\r
- { volume, 100, 0, 127, false, "Volume", ConfigType::integer, {}, "Play mode" },\r
- { scale, 0, 0, 18, false, "Scale", ConfigType::integer, {}, "Play mode" }, // NOTE: Should be options\r
- { key, 0, 0, 11, false, "Key", ConfigType::options, { "C", "C#", "D", "D#",\r
- "E", "F", "F#", "G",\r
- "G#", "A", "A#", "B"}, "Play mode" },\r
- { hideMode, 0, 0, 1, false, "Hide Mode", ConfigType::boolean, {}, "Play mode" },\r
- { chord, 0, 0, 127, false, "Chord", ConfigType::integer, {}, "Play mode" }, // NOTE: Should be options\r
- { arpPattern, 0, 0, 127, false, "Arp Pattern", ConfigType::integer, {}, "Play mode" },\r
- { tempo, 120, 1, 300, false, "Tempo", ConfigType::integer, {}, "Rhythm" },\r
- { key, 0, 0, 11, false, "Key", ConfigType::options, { "C", "C#", "D", "D#",\r
+ "Relative Bipolar" }, playGroup },\r
+ { velocitySensitivity, 100, 0, 127, false, "Strike Sensitivity", ConfigType::integer, {}, sensitivityGroup },\r
+ { glideSensitivity, 100, 0, 127, false, "Glide Sensitivity", ConfigType::integer, {}, sensitivityGroup },\r
+ { slideSensitivity, 100, 0, 127, false, "Slide Sensitivity", ConfigType::integer, {}, sensitivityGroup },\r
+ { pressureSensitivity, 100, 0, 127, false, "Pressure Sensitivity", ConfigType::integer, {}, sensitivityGroup },\r
+ { liftSensitivity, 100, 0, 127, false, "Lift Sensitivity", ConfigType::integer, {}, sensitivityGroup },\r
+ { fixedVelocity, 0, 0, 1, false, "Fixed Velocity", ConfigType::boolean, {}, sensitivityGroup },\r
+ { fixedVelocityValue, 127, 1, 127, false, "Fixed Velocity Value", ConfigType::integer, {}, sensitivityGroup },\r
+ { pianoMode, 0, 0, 1, false, "Piano Mode", ConfigType::boolean, {}, playGroup },\r
+ { glideLock, 0, 0, 127, false, "Glide Rate", ConfigType::integer, {}, playGroup },\r
+ { glideLockEnable, 0, 0, 1, false, "Glide Lock Enable", ConfigType::boolean, {}, playGroup },\r
+ { mode, 4, 1, 5, false, "Mode", ConfigType::integer, {}, playGroup },\r
+ { volume, 100, 0, 127, false, "Volume", ConfigType::integer, {}, playGroup },\r
+ { scale, 0, 0, 18, false, "Scale", ConfigType::integer, {}, playGroup }, // NOTE: Should be options\r
+ { hideMode, 0, 0, 1, false, "Hide Mode", ConfigType::boolean, {}, playGroup },\r
+ { chord, 0, 0, 127, false, "Chord", ConfigType::integer, {}, playGroup }, // NOTE: Should be options\r
+ { arpPattern, 0, 0, 127, false, "Arp Pattern", ConfigType::integer, {}, playGroup },\r
+ { tempo, 120, 1, 300, false, "Tempo", ConfigType::integer, {}, rhythmGroup },\r
+ { key, 0, 0, 11, false, "Key", ConfigType::options, { "C", "C#", "D", "D#",\r
"E", "F", "F#", "G",\r
- "G#", "A", "A#", "B"}, "Play mode" },\r
- { autoTransposeToKey, 0, 0, 1, false, "Auto Transpose To Key",ConfigType::boolean, {}, "Pitch" },\r
- { xTrackingMode, 1, 1, 4, false, "Glide Tracking Mode", ConfigType::options, { "Multi-Channel",\r
+ "G#", "A", "A#", "B"}, playGroup },\r
+ { autoTransposeToKey, 0, 0, 1, false, "Auto Transpose To Key",ConfigType::boolean, {}, pitchGroup },\r
+ { xTrackingMode, 1, 1, 4, false, "Glide Tracking Mode", ConfigType::options, { "Multi-Channel",\r
"Last Played",\r
"Highest",\r
"Lowest",\r
- "Disabled" }, "Play mode" },\r
- { yTrackingMode, 1, 1, 4, false, "Slide Tracking Mode", ConfigType::options, { "Multi-Channel",\r
+ "Disabled" }, playGroup },\r
+ { yTrackingMode, 1, 1, 4, false, "Slide Tracking Mode", ConfigType::options, { "Multi-Channel",\r
"Last Played",\r
"Highest",\r
"Lowest",\r
- "Disabled" }, "Play mode" },\r
- { zTrackingMode, 1, 0, 4, false, "Pressure Tracking Mode", ConfigType::options, { "Multi-Channel",\r
+ "Disabled" }, playGroup },\r
+ { zTrackingMode, 1, 0, 4, false, "Pressure Tracking Mode", ConfigType::options, { "Poly Aftertouch",\r
"Last Played",\r
"Highest",\r
"Lowest",\r
"Disabled",\r
- "Hardest" }, "Play mode" },\r
+ "Hardest" }, playGroup },\r
\r
- { gammaCorrection, 0, 0, 1, false, "Gamma Correction", ConfigType::boolean, {}, {} },\r
- { globalKeyColour, INT32_MIN, INT32_MIN, INT32_MAX, false, "Global Key Colour", ConfigType::colour, {}, "Colour" },\r
- { rootKeyColour, INT32_MIN, INT32_MIN, INT32_MAX, false, "Root Key Colour" , ConfigType::colour, {}, "Colour" },\r
- { brightness, 100, 0, 100, false, "Brightness", ConfigType::integer, {}, "Colour" },\r
+ { gammaCorrection, 0, 0, 1, false, "Gamma Correction", ConfigType::boolean, {}, coloursGroup },\r
+ { globalKeyColour, INT32_MIN, INT32_MIN, INT32_MAX, false, "Global Key Color", ConfigType::colour, {}, coloursGroup },\r
+ { rootKeyColour, INT32_MIN, INT32_MIN, INT32_MAX, false, "Root Key Color" , ConfigType::colour, {}, coloursGroup },\r
+ { brightness, 100, 0, 100, false, "Brightness", ConfigType::integer, {}, coloursGroup },\r
\r
// These can be defined for unique usage for a given Littlefoot script\r
- { user0, 0, 0, 127, false, {}, ConfigType::integer, {}, {} },\r
- { user1, 0, 0, 127, false, {}, ConfigType::integer, {}, {} },\r
- { user2, 0, 0, 127, false, {}, ConfigType::integer, {}, {} },\r
- { user3, 0, 0, 127, false, {}, ConfigType::integer, {}, {} },\r
- { user4, 0, 0, 127, false, {}, ConfigType::integer, {}, {} },\r
- { user5, 0, 0, 127, false, {}, ConfigType::integer, {}, {} },\r
- { user6, 0, 0, 127, false, {}, ConfigType::integer, {}, {} },\r
- { user7, 0, 0, 127, false, {}, ConfigType::integer, {}, {} },\r
- { user8, 0, 0, 127, false, {}, ConfigType::integer, {}, {} },\r
- { user9, 0, 0, 127, false, {}, ConfigType::integer, {}, {} },\r
- { user10, 0, 0, 127, false, {}, ConfigType::integer, {}, {} },\r
- { user11, 0, 0, 127, false, {}, ConfigType::integer, {}, {} },\r
- { user12, 0, 0, 127, false, {}, ConfigType::integer, {}, {} },\r
- { user13, 0, 0, 127, false, {}, ConfigType::integer, {}, {} },\r
- { user14, 0, 0, 127, false, {}, ConfigType::integer, {}, {} },\r
- { user15, 0, 0, 127, false, {}, ConfigType::integer, {}, {} },\r
- { user16, 0, 0, 127, false, {}, ConfigType::integer, {}, {} },\r
- { user17, 0, 0, 127, false, {}, ConfigType::integer, {}, {} },\r
- { user18, 0, 0, 127, false, {}, ConfigType::integer, {}, {} },\r
- { user19, 0, 0, 127, false, {}, ConfigType::integer, {}, {} },\r
- { user20, 0, 0, 127, false, {}, ConfigType::integer, {}, {} },\r
- { user21, 0, 0, 127, false, {}, ConfigType::integer, {}, {} },\r
- { user22, 0, 0, 127, false, {}, ConfigType::integer, {}, {} },\r
- { user23, 0, 0, 127, false, {}, ConfigType::integer, {}, {} },\r
- { user24, 0, 0, 127, false, {}, ConfigType::integer, {}, {} },\r
- { user25, 0, 0, 127, false, {}, ConfigType::integer, {}, {} },\r
- { user26, 0, 0, 127, false, {}, ConfigType::integer, {}, {} },\r
- { user27, 0, 0, 127, false, {}, ConfigType::integer, {}, {} },\r
- { user28, 0, 0, 127, false, {}, ConfigType::integer, {}, {} },\r
- { user29, 0, 0, 127, false, {}, ConfigType::integer, {}, {} },\r
- { user30, 0, 0, 127, false, {}, ConfigType::integer, {}, {} },\r
- { user31, 0, 0, 127, false, {}, ConfigType::integer, {}, {} }\r
+ { user0, 0, 0, 127, false, {}, ConfigType::integer, {}, {} },\r
+ { user1, 0, 0, 127, false, {}, ConfigType::integer, {}, {} },\r
+ { user2, 0, 0, 127, false, {}, ConfigType::integer, {}, {} },\r
+ { user3, 0, 0, 127, false, {}, ConfigType::integer, {}, {} },\r
+ { user4, 0, 0, 127, false, {}, ConfigType::integer, {}, {} },\r
+ { user5, 0, 0, 127, false, {}, ConfigType::integer, {}, {} },\r
+ { user6, 0, 0, 127, false, {}, ConfigType::integer, {}, {} },\r
+ { user7, 0, 0, 127, false, {}, ConfigType::integer, {}, {} },\r
+ { user8, 0, 0, 127, false, {}, ConfigType::integer, {}, {} },\r
+ { user9, 0, 0, 127, false, {}, ConfigType::integer, {}, {} },\r
+ { user10, 0, 0, 127, false, {}, ConfigType::integer, {}, {} },\r
+ { user11, 0, 0, 127, false, {}, ConfigType::integer, {}, {} },\r
+ { user12, 0, 0, 127, false, {}, ConfigType::integer, {}, {} },\r
+ { user13, 0, 0, 127, false, {}, ConfigType::integer, {}, {} },\r
+ { user14, 0, 0, 127, false, {}, ConfigType::integer, {}, {} },\r
+ { user15, 0, 0, 127, false, {}, ConfigType::integer, {}, {} },\r
+ { user16, 0, 0, 127, false, {}, ConfigType::integer, {}, {} },\r
+ { user17, 0, 0, 127, false, {}, ConfigType::integer, {}, {} },\r
+ { user18, 0, 0, 127, false, {}, ConfigType::integer, {}, {} },\r
+ { user19, 0, 0, 127, false, {}, ConfigType::integer, {}, {} },\r
+ { user20, 0, 0, 127, false, {}, ConfigType::integer, {}, {} },\r
+ { user21, 0, 0, 127, false, {}, ConfigType::integer, {}, {} },\r
+ { user22, 0, 0, 127, false, {}, ConfigType::integer, {}, {} },\r
+ { user23, 0, 0, 127, false, {}, ConfigType::integer, {}, {} },\r
+ { user24, 0, 0, 127, false, {}, ConfigType::integer, {}, {} },\r
+ { user25, 0, 0, 127, false, {}, ConfigType::integer, {}, {} },\r
+ { user26, 0, 0, 127, false, {}, ConfigType::integer, {}, {} },\r
+ { user27, 0, 0, 127, false, {}, ConfigType::integer, {}, {} },\r
+ { user28, 0, 0, 127, false, {}, ConfigType::integer, {}, {} },\r
+ { user29, 0, 0, 127, false, {}, ConfigType::integer, {}, {} },\r
+ { user30, 0, 0, 127, false, {}, ConfigType::integer, {}, {} },\r
+ { user31, 0, 0, 127, false, {}, ConfigType::integer, {}, {} }\r
};\r
\r
//==============================================================================\r
/** The release tag for this version, such as "beta", "alpha", "rc", etc */\r
String releaseType;\r
\r
- /** A numberical value assosiated with the release tag, such as "beta 4" */\r
+ /** A numerical value associated with the release tag, such as "beta 4" */\r
int releaseCount = 0;\r
\r
- /** The assosiated git commit that generated this firmware version */\r
+ /** The associated git commit that generated this firmware version */\r
String commit;\r
\r
/** Identify "forced" firmware builds **/\r
\r
/** Returns the position of this button on the device, in device units.\r
For buttons that are on the side of the device, this may want to return a value that\r
- is beyond the phyiscal block size.\r
+ is beyond the physical block size.\r
*/\r
virtual float getPositionX() const = 0;\r
\r
/** Returns the position of this button on the device, in device units.\r
For buttons that are on the side of the device, this may want to return a value that\r
- is beyond the phyiscal block size.\r
+ is beyond the physical block size.\r
*/\r
virtual float getPositionY() const = 0;\r
\r
TouchEntry* end() noexcept { return touches.end(); }\r
const TouchEntry* end() const noexcept { return touches.end(); }\r
\r
- /** Retrieve a reference to particular item in the list of touch entires. */\r
+ /** Retrieve a reference to particular item in the list of touch entries. */\r
TouchEntry& operator[] (const int index) { return touches.getReference (index); }\r
\r
/** Resets all contents, doest not generate any call-backs. */\r
#include "protocol/juce_BlocksProtocolDefinitions.h"\r
#include "protocol/juce_HostPacketDecoder.h"\r
#include "protocol/juce_HostPacketBuilder.h"\r
-#include "protocol/juce_BlockModels.h"\r
-\r
#include "blocks/juce_BlockConfigManager.h"\r
+#include "protocol/juce_BlockModels.h"\r
#include "blocks/juce_Block.cpp"\r
#include "blocks/juce_BlocksVersion.cpp"\r
#include "topology/juce_BlockGraph.cpp"\r
==============================================================================\r
*/\r
\r
+\r
/*******************************************************************************\r
The block below describes the properties of this module, and is read by\r
the Projucer to automatically generate project code that uses it.\r
\r
ID: juce_blocks_basics\r
vendor: juce\r
- version: 5.4.5\r
+ version: 5.4.6\r
name: Provides low-level control over ROLI BLOCKS devices\r
description: JUCE wrapper for low-level control over ROLI BLOCKS devices.\r
website: http://developer.roli.com\r
license: ISC\r
minimumCppStandard: 14\r
\r
- dependencies: juce_events juce_audio_devices\r
+ dependencies: juce_events juce_audio_devices\r
\r
END_JUCE_MODULE_DECLARATION\r
\r
{\r
BlockDataSheet (const BlocksProtocol::BlockSerialNumber& serial) : serialNumber (serial)\r
{\r
- if (serialNumber.isPadBlock()) initialiseForPadBlock2x2();\r
- if (serialNumber.isLiveBlock()) initialiseForControlBlockLive();\r
- if (serialNumber.isLoopBlock()) initialiseForControlBlockLoop();\r
- if (serialNumber.isDevCtrlBlock()) initialiseForControlBlockDeveloper();\r
- if (serialNumber.isTouchBlock()) initialiseForControlBlockTouch();\r
- if (serialNumber.isSeaboardBlock()) initialiseForSeaboardBlock();\r
+ if (serialNumber.isPadBlock()) initialiseForPadBlock2x2();\r
+ if (serialNumber.isLiveBlock()) initialiseForControlBlockLive();\r
+ if (serialNumber.isLoopBlock()) initialiseForControlBlockLoop();\r
+ if (serialNumber.isDevCtrlBlock()) initialiseForControlBlockDeveloper();\r
+ if (serialNumber.isTouchBlock()) initialiseForControlBlockTouch();\r
+ if (serialNumber.isSeaboardBlock()) initialiseForSeaboardBlock();\r
+ if (serialNumber.isLumiKeysBlock()) initialiseForLumiKeysBlock();\r
}\r
\r
Block::ConnectionPort convertPortIndexToConnectorPort (BlocksProtocol::ConnectorPort port) const noexcept\r
Array<StatusLEDInfo> statusLEDs;\r
Array<Block::ConnectionPort> ports;\r
Array<const char*> dials;\r
+ Array<BlockConfigManager::ConfigDescription> defaultConfig;\r
\r
private:\r
//==============================================================================\r
addModeButton();\r
}\r
\r
+ void initialiseForLumiKeysBlock()\r
+ {\r
+ apiType = Block::Type::lumiKeysBlock;\r
+\r
+ description = "LUMI Keys BLOCK (6x3)";\r
+\r
+ widthUnits = 6;\r
+ heightUnits = 3;\r
+\r
+ lightGridWidth = 0;\r
+ lightGridHeight = 0;\r
+ numKeywaves = 24;\r
+\r
+ addButtons (ControlButton::ButtonFunction::mode, 0.2f, 0.2f,\r
+ ControlButton::ButtonFunction::down, 0.6f, 0.2f,\r
+ ControlButton::ButtonFunction::up, 1.0f, 0.2f);\r
+\r
+ addPortsSW (Block::ConnectionPort::DeviceEdge::west, 2);\r
+ addPortsNE (Block::ConnectionPort::DeviceEdge::north, 4);\r
+ addPortsNE (Block::ConnectionPort::DeviceEdge::east, 2);\r
+\r
+ hasTouchSurface = true;\r
+ programAndHeapSize = BlocksProtocol::padBlockProgramAndHeapSize;\r
+\r
+ defaultConfig.add ({ mode, 0, 0, 3, false,\r
+ "Color Mode", ConfigType::options,\r
+ { "Multi-color Mode",\r
+ "Single Color Mode",\r
+ "Piano Mode",\r
+ "Night Mode"\r
+ },\r
+ BlockConfigManager::playGroup });\r
+\r
+ defaultConfig.add ({ zTrackingMode, 0, 0, 1, false,\r
+ "Pressure Tracking Mode", ConfigType::options,\r
+ { "Poly Aftertouch", "Channel Pressure" },\r
+ BlockConfigManager::playGroup });\r
+ }\r
+\r
//==============================================================================\r
void addStatusLED (const char* name, float x, float y)\r
{\r
if (c == 0)\r
return false;\r
\r
- return isAnyControlBlock() || isPadBlock() || isSeaboardBlock();\r
+ return isAnyControlBlock() || isPadBlock() || isSeaboardBlock() || isLumiKeysBlock();\r
}\r
\r
bool isPadBlock() const noexcept { return hasPrefix ("LPB") || hasPrefix ("LPM"); }\r
bool isDevCtrlBlock() const noexcept { return hasPrefix ("DCB"); }\r
bool isTouchBlock() const noexcept { return hasPrefix ("TCB"); }\r
bool isSeaboardBlock() const noexcept { return hasPrefix ("SBB"); }\r
+ bool isLumiKeysBlock() const noexcept { return hasPrefix ("LKB"); }\r
\r
bool isAnyControlBlock() const noexcept { return isLiveBlock() || isLoopBlock() || isDevCtrlBlock() || isTouchBlock(); }\r
\r
deviceInfo.name.asString()),\r
modelData (deviceInfo.serial),\r
remoteHeap (modelData.programAndHeapSize),\r
- detector (&detectorToUse)\r
+ detector (&detectorToUse),\r
+ config (modelData.defaultConfig)\r
{\r
markReconnected (deviceInfo);\r
\r
bool sendMessageToDevice (const PacketBuilder& builder)\r
{\r
if (detector != nullptr)\r
- {\r
- lastMessageSendTime = Time::getCurrentTime();\r
return detector->sendMessageToDevice (uid, builder);\r
- }\r
\r
return false;\r
}\r
\r
void pingFromDevice()\r
{\r
- lastMessageReceiveTime = Time::getCurrentTime();\r
+ lastPingReceiveTime = Time::getCurrentTime();\r
}\r
\r
MIDIDeviceConnection* getDeviceConnection()\r
\r
remoteHeap.sendChanges (*this, false);\r
\r
- if (lastMessageSendTime < Time::getCurrentTime() - getPingInterval())\r
+ if (lastPingSendTime < Time::getCurrentTime() - getPingInterval())\r
+ {\r
+ lastPingSendTime = Time::getCurrentTime();\r
sendCommandMessage (BlocksProtocol::ping);\r
+ }\r
}\r
\r
RelativeTime getPingInterval()\r
RemoteHeapType remoteHeap;\r
\r
WeakReference<Detector> detector;\r
- Time lastMessageSendTime, lastMessageReceiveTime;\r
+ Time lastPingSendTime, lastPingReceiveTime;\r
\r
BlockConfigManager config;\r
std::function<void(Block&, const ConfigMetaData&, uint32)> configChangedCallback;\r
\r
/**\r
Firmware below 0.3.0 does not report its version over the Blocks API.\r
- This class can make requests and process responses to retreive the master Block version.\r
+ This class can make requests and process responses to retrieve the master Block version.\r
*/\r
class DepreciatedVersionReader : private MIDIDeviceConnection::Listener,\r
private Timer\r
return 1;\r
}\r
}\r
+ else if (block->getType() == Block::lumiKeysBlock)\r
+ {\r
+ if (edge == Block::ConnectionPort::DeviceEdge::north)\r
+ {\r
+ switch (index)\r
+ {\r
+ case 0 : return 0;\r
+ case 1 : return 2;\r
+ case 2 : return 3;\r
+ case 3 : return 5;\r
+ default : jassertfalse;\r
+ }\r
+ }\r
+ else if (edge == Block::ConnectionPort::DeviceEdge::south)\r
+ {\r
+ jassertfalse;\r
+ }\r
+ }\r
\r
if (edge == Block::ConnectionPort::DeviceEdge::south)\r
return block->getWidth() - (index + 1);\r
bool lockedFromOutside = true;\r
\r
/** For backwards compatibility, the block interprocess lock has to use the midi input name.\r
- The below is necceccary because blocks of the same type might duplicate a port name, so\r
- must share an interporcess lock.\r
+ The below is necessary because blocks of the same type might duplicate a port name, so\r
+ must share an interprocess lock.\r
*/\r
std::shared_ptr<InterProcessLock> createMidiPortLock (const String& midiInName, const String& midiOutName)\r
{\r
\r
/**\r
Represents traversal paths from master blocks and any connected blocks.\r
+\r
+ @tags{Blocks}\r
*/\r
class BlockGraph\r
{\r
public:\r
- /** Creates a BlockGraph object from a BlockTopology with an optional filter fucntion. This\r
+ /** Creates a BlockGraph object from a BlockTopology with an optional filter function. This\r
will build a block graph of traversal paths for each master.\r
*/\r
BlockGraph (const BlockTopology topology, std::function<bool(Block::Ptr block)> filter = nullptr);\r
namespace juce\r
{\r
\r
-/** Describes a phyiscal connection between two ports of two block devices.\r
+/** Describes a physical connection between two ports of two block devices.\r
\r
@tags{Blocks}\r
*/\r
==============================================================================\r
*/\r
\r
+\r
/*******************************************************************************\r
The block below describes the properties of this module, and is read by\r
the Projucer to automatically generate project code that uses it.\r
\r
BEGIN_JUCE_MODULE_DECLARATION\r
\r
- ID: juce_box2d\r
- vendor: juce\r
- version: 5.4.5\r
- name: JUCE wrapper for the Box2D physics engine\r
- description: The Box2D physics engine and some utility classes.\r
- website: http://www.juce.com/juce\r
- license: GPL/Commercial\r
+ ID: juce_box2d\r
+ vendor: juce\r
+ version: 5.4.6\r
+ name: JUCE wrapper for the Box2D physics engine\r
+ description: The Box2D physics engine and some utility classes.\r
+ website: http://www.juce.com/juce\r
+ license: GPL/Commercial\r
\r
- dependencies: juce_graphics\r
+ dependencies: juce_graphics\r
\r
END_JUCE_MODULE_DECLARATION\r
\r
Examples of arrays are: Array<int>, Array<Rectangle> or Array<MyClass*>\r
\r
The Array class can be used to hold simple, non-polymorphic objects as well as primitive types - to\r
- do so, the class must fulfil these requirements:\r
+ do so, the class must fulfill these requirements:\r
- it must have a copy constructor and assignment operator\r
- it must be able to be relocated in memory by a memcpy without this causing any problems - so\r
objects whose functionality relies on external pointers or references to themselves can not be used.\r
checkEqual (copyableContainer, noncopyableContainer, referenceContainer);\r
}\r
\r
- beginTest ("add array from initilizer list");\r
+ beginTest ("add array from initializer_list");\r
{\r
std::vector<CopyableType> referenceContainer;\r
ArrayBase<CopyableType, DummyCriticalSection> copyableContainer;\r
call, then it invokes it.\r
\r
This method is virtual to allow more dynamic invocation to used for objects\r
- where the methods may not already be set as properies.\r
+ where the methods may not already be set as properties.\r
*/\r
virtual var invokeMethod (Identifier methodName,\r
const var::NativeFunctionArgs& args);\r
*/\r
void removeValue (StringRef keyName);\r
\r
- /** Returns true if the properies include the given key. */\r
+ /** Returns true if the properties include the given key. */\r
bool containsKey (StringRef keyName) const noexcept;\r
\r
/** Removes all values. */\r
PropertySet* getFallbackPropertySet() const noexcept { return fallbackProperties; }\r
\r
protected:\r
- /** Subclasses can override this to be told when one of the properies has been changed. */\r
+ /** Subclasses can override this to be told when one of the properties has been changed. */\r
virtual void propertyChanged();\r
\r
private:\r
int64 int64Value;\r
bool boolValue;\r
double doubleValue;\r
- char stringValue [sizeof (String)];\r
+ char stringValue[sizeof (String)];\r
ReferenceCountedObject* objectValue;\r
MemoryBlock* binaryValue;\r
NativeFunction* methodValue;\r
// This is needed to prevent the wrong constructor/operator being called\r
var (const ReferenceCountedObject*) = delete;\r
var& operator= (const ReferenceCountedObject*) = delete;\r
+ var (const void*) = delete;\r
+ var& operator= (const void*) = delete;\r
};\r
\r
/** Compares the values of two var objects, using the var::equals() comparison. */\r
return path;\r
}\r
\r
+static String normaliseSeparators (const String& path)\r
+{\r
+ auto normalisedPath = path;\r
+\r
+ String separator (File::getSeparatorString());\r
+ String doubleSeparator (separator + separator);\r
+\r
+ auto uncPath = normalisedPath.startsWith (doubleSeparator)\r
+ && ! normalisedPath.fromFirstOccurrenceOf (doubleSeparator, false, false).startsWith (separator);\r
+\r
+ if (uncPath)\r
+ normalisedPath = normalisedPath.fromFirstOccurrenceOf (doubleSeparator, false, false);\r
+\r
+ while (normalisedPath.contains (doubleSeparator))\r
+ normalisedPath = normalisedPath.replace (doubleSeparator, separator);\r
+\r
+ return uncPath ? doubleSeparator + normalisedPath\r
+ : normalisedPath;\r
+}\r
+\r
bool File::isRoot() const\r
{\r
return fullPath.isNotEmpty() && *this == getParentDirectory();\r
if (p.isEmpty())\r
return {};\r
\r
-#if JUCE_WINDOWS\r
+ #if JUCE_WINDOWS\r
// Windows..\r
- auto path = removeEllipsis (p.replaceCharacter ('/', '\\'));\r
+ auto path = normaliseSeparators (removeEllipsis (p.replaceCharacter ('/', '\\')));\r
\r
if (path.startsWithChar (getSeparatorChar()))\r
{\r
\r
return File::getCurrentWorkingDirectory().getChildFile (path).getFullPathName();\r
}\r
-#else\r
+ #else\r
// Mac or Linux..\r
\r
// Yes, I know it's legal for a unix pathname to contain a backslash, but this assertion is here\r
// If that's why you've ended up here, use File::getChildFile() to build your paths instead.\r
jassert ((! p.containsChar ('\\')) || (p.indexOfChar ('/') >= 0 && p.indexOfChar ('/') < p.indexOfChar ('\\')));\r
\r
- auto path = removeEllipsis (p);\r
+ auto path = normaliseSeparators (removeEllipsis (p));\r
\r
if (path.startsWithChar ('~'))\r
{\r
\r
return File::getCurrentWorkingDirectory().getChildFile (path).getFullPathName();\r
}\r
-#endif\r
+ #endif\r
\r
while (path.endsWithChar (getSeparatorChar()) && path != getSeparatorString()) // careful not to turn a single "/" into an empty string.\r
path = path.dropLastCharacters (1);\r
for (int i = 0; i < values.size(); ++i)\r
a.add (values.getUnchecked(i)->getResult (s));\r
\r
- return a;\r
+ // std::move() needed here for older compilers\r
+ return std::move (a);\r
}\r
\r
OwnedArray<Expression> values;\r
for (int i = 2; i < a.numArguments; ++i)\r
array->insert (start++, get (a, i));\r
\r
- return itemsRemoved;\r
+ // std::move() needed here for older compilers\r
+ return std::move (itemsRemoved);\r
}\r
\r
return var::undefined();\r
#include <android/log.h>\r
#endif\r
\r
-#if JUCE_BELA\r
- #include <alchemy/timer.h>\r
-#endif\r
-\r
#undef check\r
\r
//==============================================================================\r
#include "misc/juce_RuntimePermissions.cpp"\r
#include "misc/juce_Result.cpp"\r
#include "misc/juce_Uuid.cpp"\r
-#include "misc/juce_StdFunctionCompat.cpp"\r
#include "misc/juce_ConsoleApplication.cpp"\r
#include "network/juce_MACAddress.cpp"\r
#include "network/juce_NamedPipe.cpp"\r
\r
#include "threads/juce_ChildProcess.cpp"\r
#include "threads/juce_HighResolutionTimer.cpp"\r
+#include "threads/juce_WaitableEvent.cpp"\r
#include "network/juce_URL.cpp"\r
#include "network/juce_WebInputStream.cpp"\r
#include "streams/juce_URLInputSource.cpp"\r
\r
BEGIN_JUCE_MODULE_DECLARATION\r
\r
- ID: juce_core\r
- vendor: juce\r
- version: 5.4.5\r
- name: JUCE core classes\r
- 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.\r
- website: http://www.juce.com/juce\r
- license: ISC\r
+ ID: juce_core\r
+ vendor: juce\r
+ version: 5.4.6\r
+ name: JUCE core classes\r
+ 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.\r
+ website: http://www.juce.com/juce\r
+ license: ISC\r
\r
dependencies:\r
- OSXFrameworks: Cocoa IOKit\r
- iOSFrameworks: Foundation\r
- linuxLibs: rt dl pthread\r
- mingwLibs: uuid wsock32 wininet version ole32 ws2_32 oleaut32 imm32 comdlg32 shlwapi rpcrt4 winmm\r
+ OSXFrameworks: Cocoa IOKit\r
+ iOSFrameworks: Foundation\r
+ linuxLibs: rt dl pthread\r
+ mingwLibs: uuid wsock32 wininet version ole32 ws2_32 oleaut32 imm32 comdlg32 shlwapi rpcrt4 winmm\r
\r
END_JUCE_MODULE_DECLARATION\r
\r
\r
/** Config: JUCE_LOAD_CURL_SYMBOLS_LAZILY\r
If enabled, JUCE will load libcurl lazily when required (for example, when WebInputStream\r
- is used). Enabling this flag may also help with library dependency erros as linking\r
+ is used). Enabling this flag may also help with library dependency errors as linking\r
libcurl at compile-time may instruct the linker to hard depend on a specific version\r
of libcurl. It's also useful if you want to limit the amount of JUCE dependencies and\r
you are not using WebInputStream or the URL classes.\r
\r
The filename used is based on the root and suffix strings provided, along with a\r
time and date string, meaning that a new, empty log file will be always be created\r
- rather than appending to an exising one.\r
+ rather than appending to an existing one.\r
\r
The method might return nullptr if the file can't be created for some reason.\r
\r
Once a new ReferenceCountedObject has been assigned to a pointer, be\r
careful not to delete the object manually.\r
\r
- This class uses an Atomic<int> value to hold the reference count, so that\r
- the pointers can be passed between threads safely. For a faster but non-thread-safe\r
- version, use SingleThreadedReferenceCountedObject instead.\r
+ This class uses an Atomic<int> value to hold the reference count, so\r
+ the reference count can be updated on multiple threads. Note that\r
+ whilst it's thread-safe to create and delete a ReferenceCountedObjectPtr\r
+ to a ReferenceCountedObject shared between threads, it's not thread-safe\r
+ to modify or swap the ReferenceCountedObject.\r
+\r
+ For a faster but non-thread-safe version, use SingleThreadedReferenceCountedObject\r
+ instead.\r
\r
@see ReferenceCountedObjectPtr, ReferenceCountedArray, SingleThreadedReferenceCountedObject\r
\r
}\r
catch (const ConsoleAppFailureCode& error)\r
{\r
- std::cout << error.errorMessage << std::endl;\r
+ std::cerr << error.errorMessage << std::endl;\r
returnCode = error.returnCode;\r
}\r
\r
main() function to parse.\r
\r
@see ConsoleApplication\r
+\r
+ @tags{Core}\r
*/\r
struct ArgumentList\r
{\r
//==============================================================================\r
/**\r
One of the arguments in an ArgumentList.\r
+\r
+ @tags{Core}\r
*/\r
struct Argument\r
{\r
@endcode\r
\r
@see ArgumentList\r
+\r
+ @tags{Core}\r
*/\r
struct ConsoleApplication\r
{\r
//==============================================================================\r
/**\r
Represents a command that can be executed if its command-line arguments are matched.\r
+\r
@see ConsoleApplication::addCommand(), ConsoleApplication::findAndRunCommand()\r
+\r
+ @tags{Core}\r
*/\r
struct Command\r
{\r
+++ /dev/null
-/*\r
- ==============================================================================\r
-\r
- This file is part of the JUCE library.\r
- Copyright (c) 2017 - ROLI Ltd.\r
-\r
- Permission is granted to use this software under the terms of the ISC license\r
- http://www.isc.org/downloads/software-support-policy/isc-license/\r
-\r
- Permission to use, copy, modify, and/or distribute this software for any\r
- purpose with or without fee is hereby granted, provided that the above\r
- copyright notice and this permission notice appear in all copies.\r
-\r
- THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH REGARD\r
- TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND\r
- FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT,\r
- OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF\r
- USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER\r
- TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE\r
- OF THIS SOFTWARE.\r
-\r
- -----------------------------------------------------------------------------\r
-\r
- To release a closed-source product which uses other parts of JUCE not\r
- licensed under the ISC terms, commercial licenses are available: visit\r
- www.juce.com for more information.\r
-\r
- ==============================================================================\r
-*/\r
-\r
-namespace juce\r
-{\r
-\r
-#if JUCE_UNIT_TESTS\r
-\r
-namespace FunctionTestsHelpers\r
-{\r
- static void incrementArgument (int& x) { x++; }\r
- static double multiply (double x, double a) noexcept { return a * x; }\r
-\r
- struct BigData\r
- {\r
- BigData()\r
- {\r
- for (auto i = 0; i < bigDataSize; ++i)\r
- content[i] = i + 1;\r
- }\r
-\r
- int sum() const\r
- {\r
- int result = 0;\r
- for (auto i = 0; i < bigDataSize; ++i)\r
- result += content[i];\r
-\r
- return result;\r
- }\r
-\r
- static const int bigDataSize = 32,\r
- bigDataSum = bigDataSize * (bigDataSize + 1) / 2;\r
- int content[bigDataSize];\r
- };\r
-\r
- struct FunctionObject\r
- {\r
- FunctionObject() = default;\r
-\r
- FunctionObject (const FunctionObject& other)\r
- {\r
- bigData.reset (new BigData (*other.bigData));\r
- }\r
-\r
- int operator()(int i) const { return bigData->sum() + i; }\r
-\r
- std::unique_ptr<BigData> bigData { new BigData() };\r
-\r
- JUCE_LEAK_DETECTOR (FunctionObject)\r
- };\r
-\r
- struct BigFunctionObject\r
- {\r
- BigFunctionObject() = default;\r
-\r
- BigFunctionObject (const BigFunctionObject& other)\r
- {\r
- bigData.reset (new BigData (*other.bigData));\r
- }\r
-\r
- int operator()(int i) const { return bigData->sum() + i; }\r
-\r
- std::unique_ptr<BigData> bigData { new BigData() };\r
-\r
- int stackUsage[32];\r
-\r
- JUCE_LEAK_DETECTOR (BigFunctionObject)\r
- };\r
-}\r
-\r
-class FunctionTests : public UnitTest\r
-{\r
-public:\r
- FunctionTests()\r
- : UnitTest ("Function", UnitTestCategories::function)\r
- {}\r
-\r
- void runTest() override\r
- {\r
- FunctionTestsHelpers::BigData bigData;\r
-\r
- {\r
- beginTest ("Functions");\r
-\r
- std::function<void(int&)> f1 (FunctionTestsHelpers::incrementArgument);\r
-\r
- auto x = 0;\r
- f1 (x);\r
- expectEquals (x, 1);\r
-\r
- std::function<double(double, double)> f2 (FunctionTestsHelpers::multiply);\r
- expectEquals (6.0, f2 (2.0, 3.0));\r
- }\r
-\r
- {\r
- beginTest ("Function objects");\r
-\r
- std::function<int(int)> f1 = FunctionTestsHelpers::FunctionObject();\r
- expectEquals (f1 (5), FunctionTestsHelpers::BigData::bigDataSum + 5);\r
-\r
- std::function<int(int)> f2 { FunctionTestsHelpers::BigFunctionObject() };\r
- expectEquals (f2 (5), FunctionTestsHelpers::BigData::bigDataSum + 5);\r
- }\r
-\r
- {\r
- beginTest ("Lambdas");\r
-\r
- std::function<int()> fStack ([] { return 3; });\r
- expectEquals (fStack(), 3);\r
-\r
- std::function<int()> fHeap ([=] { return bigData.sum(); });\r
- expectEquals (fHeap(), FunctionTestsHelpers::BigData::bigDataSum);\r
- }\r
-\r
- {\r
- beginTest ("Boolean");\r
-\r
- std::function<void(int&)> f1;\r
-\r
- if (f1)\r
- expect (false);\r
-\r
- std::function<int()> f2 ([]() { return 3; });\r
-\r
- if (! f2)\r
- expect (false);\r
- }\r
-\r
- std::function<int()> fEmpty;\r
-\r
- std::function<int()> fStack ([] { return 3; });\r
-\r
- std::function<int()> fHeap ([=] { return bigData.sum(); });\r
-\r
- {\r
- beginTest ("copy constructor");\r
-\r
- std::function<int()> f1 (fStack);\r
- expectEquals (f1(), 3);\r
-\r
- std::function<int()> f2 (fHeap);\r
- expectEquals (f2(), FunctionTestsHelpers::BigData::bigDataSum);\r
-\r
- std::function<int()> f3 (fEmpty);\r
- if (f3)\r
- expect (false);\r
- }\r
-\r
- {\r
- beginTest ("assignment");\r
-\r
- std::function<int()> f1;\r
- f1 = fStack;\r
- expectEquals (f1(), 3);\r
-\r
- std::function<int()> f2;\r
- f2 = fHeap;\r
- expectEquals (f2(), FunctionTestsHelpers::BigData::bigDataSum);\r
-\r
- f1 = fHeap;\r
- expectEquals (f1(), FunctionTestsHelpers::BigData::bigDataSum);\r
-\r
- f2 = fStack;\r
- expectEquals (f2(), 3);\r
-\r
- f1 = fEmpty;\r
- if (f1)\r
- expect (false);\r
- }\r
-\r
- {\r
- beginTest ("move constructor");\r
-\r
- std::unique_ptr<std::function<int()>> fStackTmp (new std::function<int()> (fStack));\r
- std::function<int()> f1 (std::move (*fStackTmp));\r
-\r
- fStackTmp.reset();\r
- expectEquals (f1(), 3);\r
-\r
- std::unique_ptr<std::function<int()>> fHeapTmp (new std::function<int()> (fHeap));\r
- std::function<int()> f2 (std::move (*fHeapTmp));\r
- if (*fHeapTmp)\r
- expect (false);\r
-\r
- fHeapTmp.reset();\r
- expectEquals (f2(), FunctionTestsHelpers::BigData::bigDataSum);\r
-\r
- std::unique_ptr<std::function<int()>> fEmptyTmp (new std::function<int()>());\r
- std::function<int()> f3 (std::move (*fEmptyTmp));\r
- fEmptyTmp.reset();\r
- if (f3)\r
- expect (false);\r
- }\r
-\r
- {\r
- beginTest ("move assignment");\r
-\r
- std::function<int()> f1 (fHeap);\r
- std::unique_ptr<std::function<int()>> fStackTmp (new std::function<int()> (fStack));\r
- f1 = std::move (*fStackTmp);\r
-\r
- fStackTmp.reset();\r
- expectEquals (f1(), 3);\r
-\r
- std::function<int()> f2 (fStack);\r
- std::unique_ptr<std::function<int()>> fHeapTmp (new std::function<int()> (fHeap));\r
- f2 = std::move (*fHeapTmp);\r
- if (*fHeapTmp)\r
- expect (false);\r
-\r
- fHeapTmp.reset();\r
- expectEquals (f2(), FunctionTestsHelpers::BigData::bigDataSum);\r
-\r
- std::function<int()> f3 (fHeap);\r
- std::unique_ptr<std::function<int()>> fEmptyTmp (new std::function<int()>());\r
- f3 = std::move (*fEmptyTmp);\r
- fEmptyTmp.reset();\r
- if (f3)\r
- expect (false);\r
- }\r
-\r
- {\r
- beginTest ("nullptr");\r
-\r
- std::function<int()> f1 (nullptr);\r
- if (f1)\r
- expect (false);\r
-\r
- std::function<int()> f2 ([]() { return 11; });\r
- f2 = nullptr;\r
- if (f2)\r
- expect (false);\r
- }\r
-\r
- {\r
- beginTest ("Swap");\r
-\r
- std::function<int()> f1;\r
- std::function<int()> f2 (fStack);\r
- f2.swap (f1);\r
- expectEquals (f1(), 3);\r
- if (f2)\r
- expect (false);\r
-\r
- std::function<int()> f3 (fHeap);\r
- f3.swap (f1);\r
- expectEquals (f3(), 3);\r
- expectEquals (f1(), FunctionTestsHelpers::BigData::bigDataSum);\r
- }\r
- }\r
-};\r
-\r
-static FunctionTests functionTests;\r
-\r
-#endif\r
-\r
-} // namespace juce\r
+++ /dev/null
-/*\r
- ==============================================================================\r
-\r
- This file is part of the JUCE library.\r
- Copyright (c) 2017 - ROLI Ltd.\r
-\r
- Permission is granted to use this software under the terms of the ISC license\r
- http://www.isc.org/downloads/software-support-policy/isc-license/\r
-\r
- Permission to use, copy, modify, and/or distribute this software for any\r
- purpose with or without fee is hereby granted, provided that the above\r
- copyright notice and this permission notice appear in all copies.\r
-\r
- THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH REGARD\r
- TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND\r
- FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT,\r
- OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF\r
- USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER\r
- TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE\r
- OF THIS SOFTWARE.\r
-\r
- -----------------------------------------------------------------------------\r
-\r
- To release a closed-source product which uses other parts of JUCE not\r
- licensed under the ISC terms, commercial licenses are available: visit\r
- www.juce.com for more information.\r
-\r
- ==============================================================================\r
-*/\r
-\r
-namespace std\r
-{\r
- /**\r
- This class provides an alternative to std::function that is compatible\r
- with OS X 10.6 and earlier. This will only be used in OS X versions 10.6\r
- and earlier and the Projucer live build.\r
-\r
- @tags{Core}\r
- */\r
- template <typename>\r
- class function;\r
-\r
- #ifndef DOXYGEN\r
- template <typename Result, typename... Arguments>\r
- class function<Result (Arguments...)>\r
- {\r
- public:\r
- /** Creates an empty function. */\r
- function() noexcept {}\r
-\r
- /** Creates an empty function. */\r
- function (decltype (nullptr)) noexcept {}\r
-\r
- /** Creates a function targeting the provided Functor. */\r
- template <typename Functor>\r
- function (Functor f)\r
- {\r
- functorHolderHelper = getFunctorStorage (sizeof (FunctorHolder<Functor, Result, Arguments...>));\r
- new (functorHolderHelper) FunctorHolder<Functor, Result, Arguments...> (f);\r
- }\r
-\r
- /** Copy constructor. */\r
- function (function const& other)\r
- {\r
- copy (other);\r
- }\r
-\r
- /** Move constructor */\r
- function (function&& other)\r
- {\r
- move (other);\r
- }\r
-\r
- /** Destructor. */\r
- ~function()\r
- {\r
- release();\r
- }\r
-\r
- /** Replaces the contents of this function with the contents of another. */\r
- function& operator= (function const& other)\r
- {\r
- release();\r
- copy (other);\r
-\r
- return *this;\r
- }\r
-\r
- /** Moves the contents of another function into this one. */\r
- function& operator= (function&& other)\r
- {\r
- release();\r
- move (other);\r
-\r
- return *this;\r
- }\r
-\r
- /** Allows conditional expressions to test if this function is empty. */\r
- explicit operator bool() const noexcept\r
- {\r
- return functorHolderHelper != nullptr;\r
- }\r
-\r
- /** Swaps the contents of this function with another. After this operation the\r
- two functions will be pointing at each other's targets. */\r
- void swap (function& other)\r
- {\r
- function<Result (Arguments...)> tmp (*this);\r
- *this = other;\r
- other = tmp;\r
- }\r
-\r
- /** Invokes the target of this function. */\r
- Result operator() (Arguments... args) const\r
- {\r
- return (*functorHolderHelper) (std::forward<Arguments> (args)...);\r
- }\r
-\r
- bool operator== (decltype (nullptr)) const noexcept { return (functorHolderHelper == nullptr); }\r
- bool operator!= (decltype (nullptr)) const noexcept { return (functorHolderHelper != nullptr); }\r
-\r
- private:\r
- //==============================================================================\r
- template <typename ReturnType, typename... Args>\r
- struct FunctorHolderBase\r
- {\r
- virtual ~FunctorHolderBase() {}\r
- virtual int getSize() const noexcept = 0;\r
- virtual void copy (void*) const = 0;\r
- virtual ReturnType operator()(Args...) = 0;\r
- };\r
-\r
- template <typename Functor, typename ReturnType, typename... Args>\r
- struct FunctorHolder : FunctorHolderBase<Result, Arguments...>\r
- {\r
- FunctorHolder (Functor func) : f (func) {}\r
-\r
- int getSize() const noexcept override final\r
- {\r
- return sizeof (*this);\r
- }\r
-\r
- void copy (void* destination) const override final\r
- {\r
- new (destination) FunctorHolder (f);\r
- }\r
-\r
- ReturnType operator()(Args... args) override final\r
- {\r
- return f (std::forward<Arguments> (args)...);\r
- }\r
-\r
- Functor f;\r
- };\r
-\r
- FunctorHolderBase<Result, Arguments...>* getFunctorStorage (int size)\r
- {\r
- return reinterpret_cast<FunctorHolderBase<Result, Arguments...>*>\r
- (size > functorHolderStackSize ? new char [static_cast<unsigned long> (size)]\r
- : &(stackFunctorStorage[0]));\r
- }\r
-\r
- void copy (function const& other)\r
- {\r
- if (other.functorHolderHelper != nullptr)\r
- {\r
- functorHolderHelper = getFunctorStorage (other.functorHolderHelper->getSize());\r
- other.functorHolderHelper->copy (functorHolderHelper);\r
- }\r
- }\r
-\r
- void move (function& other)\r
- {\r
- if (other.functorHolderHelper != nullptr)\r
- {\r
- if (other.functorHolderHelper->getSize() > functorHolderStackSize)\r
- {\r
- functorHolderHelper = other.functorHolderHelper;\r
- }\r
- else\r
- {\r
- std::copy (other.stackFunctorStorage, other.stackFunctorStorage + functorHolderStackSize,\r
- stackFunctorStorage);\r
- functorHolderHelper = reinterpret_cast<FunctorHolderBase<Result, Arguments...>*> (&(stackFunctorStorage[0]));\r
- }\r
-\r
- other.functorHolderHelper = nullptr;\r
- }\r
- }\r
-\r
- void release()\r
- {\r
- if (functorHolderHelper != nullptr)\r
- {\r
- functorHolderHelper->~FunctorHolderBase<Result, Arguments...>();\r
- functorHolderHelper = nullptr;\r
- }\r
- }\r
-\r
- static const int functorHolderStackSize = 24;\r
- char stackFunctorStorage[functorHolderStackSize];\r
-\r
- FunctorHolderBase<Result, Arguments...>* functorHolderHelper = nullptr;\r
- };\r
- #endif\r
-}\r
DECLARE_JNI_CLASS (AndroidInputStream, "java/io/InputStream")\r
#undef JNI_CLASS_MEMBERS\r
\r
+//==============================================================================\r
+#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \\r
+ METHOD (acquire, "acquire", "()V") \\r
+ METHOD (release, "release", "()V") \\r
+\r
+DECLARE_JNI_CLASS (AndroidMulticastLock, "android/net/wifi/WifiManager$MulticastLock")\r
+#undef JNI_CLASS_MEMBERS\r
+\r
+#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \\r
+ METHOD (createMulticastLock, "createMulticastLock", "(Ljava/lang/String;)Landroid/net/wifi/WifiManager$MulticastLock;") \\r
+\r
+DECLARE_JNI_CLASS (AndroidWifiManager, "android/net/wifi/WifiManager")\r
+#undef JNI_CLASS_MEMBERS\r
+\r
+static LocalRef<jobject> getMulticastLock()\r
+{\r
+ static LocalRef<jobject> multicastLock;\r
+ static bool hasChecked = false;\r
+\r
+ if (! hasChecked)\r
+ {\r
+ hasChecked = true;\r
+\r
+ auto* env = getEnv();\r
+\r
+ LocalRef<jobject> wifiManager (env->CallObjectMethod (getAppContext().get(),\r
+ AndroidContext.getSystemService,\r
+ javaString ("wifi").get()));\r
+\r
+ if (wifiManager != nullptr)\r
+ {\r
+ multicastLock = LocalRef<jobject> (env->CallObjectMethod (wifiManager.get(),\r
+ AndroidWifiManager.createMulticastLock,\r
+ javaString ("JUCE_MulticastLock").get()));\r
+ }\r
+ }\r
+\r
+ return multicastLock;\r
+}\r
+\r
+JUCE_API void JUCE_CALLTYPE acquireMulticastLock()\r
+{\r
+ auto multicastLock = getMulticastLock();\r
+\r
+ if (multicastLock != nullptr)\r
+ getEnv()->CallVoidMethod (multicastLock.get(), AndroidMulticastLock.acquire);\r
+}\r
+\r
+JUCE_API void JUCE_CALLTYPE releaseMulticastLock()\r
+{\r
+ auto multicastLock = getMulticastLock();\r
+\r
+ if (multicastLock != nullptr)\r
+ getEnv()->CallVoidMethod (multicastLock.get(), AndroidMulticastLock.release);\r
+}\r
+\r
//==============================================================================\r
void MACAddress::findAllAddresses (Array<MACAddress>& /*result*/)\r
{\r
==============================================================================\r
*/\r
\r
+#if JUCE_BELA\r
+extern "C" int cobalt_thread_mode();\r
+#endif\r
\r
namespace juce\r
{\r
auto flags = getCpuInfo ("flags");\r
\r
hasMMX = flags.contains ("mmx");\r
+ hasFMA3 = flags.contains ("fma");\r
+ hasFMA4 = flags.contains ("fma4");\r
hasSSE = flags.contains ("sse");\r
hasSSE2 = flags.contains ("sse2");\r
hasSSE3 = flags.contains ("sse3");\r
\r
int64 Time::getHighResolutionTicks() noexcept\r
{\r
+ timespec t;\r
+\r
#if JUCE_BELA\r
- return rt_timer_read() / 1000;\r
+ if (cobalt_thread_mode() == 0x200 /*XNRELAX*/)\r
+ clock_gettime (CLOCK_MONOTONIC, &t);\r
+ else\r
+ __wrap_clock_gettime (CLOCK_MONOTONIC, &t);\r
#else\r
- timespec t;\r
clock_gettime (CLOCK_MONOTONIC, &t);\r
- return (t.tv_sec * (int64) 1000000) + (t.tv_nsec / 1000);\r
#endif\r
+\r
+ return (t.tv_sec * (int64) 1000000) + (t.tv_nsec / 1000);\r
}\r
\r
int64 Time::getHighResolutionTicksPerSecond() noexcept\r
==============================================================================\r
*/\r
\r
-\r
-// This hack is a workaround for a bug (?) in Apple's 10.11 SDK headers\r
-// which cause some configurations of Clang to throw out a spurious error..\r
#if JUCE_PROJUCER_LIVE_BUILD && (defined (__APPLE_CPP__) || defined(__APPLE_CC__))\r
+\r
+ // This hack is a workaround for a bug (?) in Apple's 10.11 SDK headers\r
+ // which cause some configurations of Clang to throw out a spurious error..\r
#include <CoreFoundation/CFAvailability.h>\r
#undef CF_OPTIONS\r
#define CF_OPTIONS(_type, _name) _type _name; enum\r
#define _Nullable\r
#define _Nonnull\r
\r
- // In later versions of libc++ these methods are defined in the functional header,\r
- // which we don't compile in the live-build engine, so we'll define them here\r
- #if defined (_LIBCPP_VERSION) && _LIBCPP_VERSION >= 7000\r
- #include <memory>\r
-\r
- namespace std { inline namespace __1 {\r
- template <class _BinaryPredicate, class _ForwardIterator1, class _ForwardIterator2>\r
- pair<_ForwardIterator1, _ForwardIterator1> _LIBCPP_CONSTEXPR_AFTER_CXX11\r
- __search(_ForwardIterator1 __first1, _ForwardIterator1 __last1,\r
- _ForwardIterator2 __first2, _ForwardIterator2 __last2, _BinaryPredicate __pred,\r
- forward_iterator_tag, forward_iterator_tag)\r
- {\r
- if (__first2 == __last2)\r
- return make_pair(__first1, __first1); // Everything matches an empty sequence\r
- while (true)\r
- {\r
- // Find first element in sequence 1 that matchs *__first2, with a mininum of loop checks\r
- while (true)\r
- {\r
- if (__first1 == __last1) // return __last1 if no element matches *__first2\r
- return make_pair(__last1, __last1);\r
- if (__pred(*__first1, *__first2))\r
- break;\r
- ++__first1;\r
- }\r
- // *__first1 matches *__first2, now match elements after here\r
- _ForwardIterator1 __m1 = __first1;\r
- _ForwardIterator2 __m2 = __first2;\r
- while (true)\r
- {\r
- if (++__m2 == __last2) // If pattern exhausted, __first1 is the answer (works for 1 element pattern)\r
- return make_pair(__first1, __m1);\r
- if (++__m1 == __last1) // Otherwise if source exhaused, pattern not found\r
- return make_pair(__last1, __last1);\r
- if (!__pred(*__m1, *__m2)) // if there is a mismatch, restart with a new __first1\r
- {\r
- ++__first1;\r
- break;\r
- } // else there is a match, check next elements\r
- }\r
- }\r
- }\r
-\r
- template <class _BinaryPredicate, class _RandomAccessIterator1, class _RandomAccessIterator2>\r
- _LIBCPP_CONSTEXPR_AFTER_CXX11\r
- pair<_RandomAccessIterator1, _RandomAccessIterator1>\r
- __search(_RandomAccessIterator1 __first1, _RandomAccessIterator1 __last1,\r
- _RandomAccessIterator2 __first2, _RandomAccessIterator2 __last2, _BinaryPredicate __pred,\r
- random_access_iterator_tag, random_access_iterator_tag)\r
- {\r
- typedef typename iterator_traits<_RandomAccessIterator1>::difference_type _D1;\r
- typedef typename iterator_traits<_RandomAccessIterator2>::difference_type _D2;\r
- // Take advantage of knowing source and pattern lengths. Stop short when source is smaller than pattern\r
- const _D2 __len2 = __last2 - __first2;\r
- if (__len2 == 0)\r
- return make_pair(__first1, __first1);\r
- const _D1 __len1 = __last1 - __first1;\r
- if (__len1 < __len2)\r
- return make_pair(__last1, __last1);\r
- const _RandomAccessIterator1 __s = __last1 - (__len2 - 1); // Start of pattern match can't go beyond here\r
-\r
- while (true)\r
- {\r
- while (true)\r
- {\r
- if (__first1 == __s)\r
- return make_pair(__last1, __last1);\r
- if (__pred(*__first1, *__first2))\r
- break;\r
- ++__first1;\r
- }\r
-\r
- _RandomAccessIterator1 __m1 = __first1;\r
- _RandomAccessIterator2 __m2 = __first2;\r
- while (true)\r
- {\r
- if (++__m2 == __last2)\r
- return make_pair(__first1, __first1 + __len2);\r
- ++__m1; // no need to check range on __m1 because __s guarantees we have enough source\r
- if (!__pred(*__m1, *__m2))\r
- {\r
- ++__first1;\r
- break;\r
- }\r
- }\r
- }\r
- }\r
- } }\r
- #endif\r
+ // A workaround for compiling the 10.15 headers with an older compiler version\r
+ #undef API_UNAVAILABLE_BEGIN\r
+ #define API_UNAVAILABLE_BEGIN(...)\r
+ #undef API_UNAVAILABLE_END\r
+ #define API_UNAVAILABLE_END\r
#endif\r
NSWorkspace* workspace = [NSWorkspace sharedWorkspace];\r
\r
if (parameters.isEmpty())\r
- // NB: the length check here is because of strange failures involving long filenames,\r
- // probably due to filesystem name length limitations..\r
- return (fileName.length() < 1024 && [workspace openFile: juceStringToNS (fileName)])\r
- || [workspace openURL: filenameAsURL];\r
+ return [workspace openURL: filenameAsURL];\r
\r
const File file (fileName);\r
\r
has3DNow = (b & (1u << 31)) != 0;\r
hasSSE3 = (c & (1u << 0)) != 0;\r
hasSSSE3 = (c & (1u << 9)) != 0;\r
+ hasFMA3 = (c & (1u << 12)) != 0;\r
hasSSE41 = (c & (1u << 19)) != 0;\r
hasSSE42 = (c & (1u << 20)) != 0;\r
hasAVX = (c & (1u << 28)) != 0;\r
\r
+ SystemStatsHelpers::doCPUID (a, b, c, d, 0x80000001);\r
+ hasFMA4 = (c & (1u << 16)) != 0;\r
+\r
SystemStatsHelpers::doCPUID (a, b, c, d, 7);\r
hasAVX2 = (b & (1u << 5)) != 0;\r
hasAVX512F = (b & (1u << 16)) != 0;\r
}\r
}\r
\r
-JUCE_API void JUCE_CALLTYPE Process::raisePrivilege()\r
-{\r
- jassertfalse;\r
-}\r
+JUCE_API void JUCE_CALLTYPE Process::raisePrivilege() {}\r
+JUCE_API void JUCE_CALLTYPE Process::lowerPrivilege() {}\r
\r
-JUCE_API void JUCE_CALLTYPE Process::lowerPrivilege()\r
-{\r
- jassertfalse;\r
-}\r
-\r
-JUCE_API void JUCE_CALLTYPE Process::setPriority (ProcessPriority)\r
-{\r
- // xxx\r
-}\r
+JUCE_API void JUCE_CALLTYPE Process::setPriority (ProcessPriority) {}\r
\r
//==============================================================================\r
JUCE_API bool JUCE_CALLTYPE juce_isRunningUnderDebugger() noexcept\r
bool CriticalSection::tryEnter() const noexcept { return pthread_mutex_trylock (&lock) == 0; }\r
void CriticalSection::exit() const noexcept { pthread_mutex_unlock (&lock); }\r
\r
-//==============================================================================\r
-WaitableEvent::WaitableEvent (bool useManualReset) noexcept\r
- : triggered (false), manualReset (useManualReset)\r
-{\r
- pthread_cond_init (&condition, {});\r
-\r
- pthread_mutexattr_t atts;\r
- pthread_mutexattr_init (&atts);\r
- #if ! JUCE_ANDROID\r
- pthread_mutexattr_setprotocol (&atts, PTHREAD_PRIO_INHERIT);\r
- #endif\r
- pthread_mutex_init (&mutex, &atts);\r
- pthread_mutexattr_destroy (&atts);\r
-}\r
-\r
-WaitableEvent::~WaitableEvent() noexcept\r
-{\r
- pthread_cond_destroy (&condition);\r
- pthread_mutex_destroy (&mutex);\r
-}\r
-\r
-bool WaitableEvent::wait (int timeOutMillisecs) const noexcept\r
-{\r
- pthread_mutex_lock (&mutex);\r
-\r
- if (! triggered)\r
- {\r
- if (timeOutMillisecs < 0)\r
- {\r
- do\r
- {\r
- pthread_cond_wait (&condition, &mutex);\r
- }\r
- while (! triggered);\r
- }\r
- else\r
- {\r
- struct timeval now;\r
- gettimeofday (&now, nullptr);\r
-\r
- struct timespec time;\r
- time.tv_sec = now.tv_sec + (timeOutMillisecs / 1000);\r
- time.tv_nsec = (now.tv_usec + ((timeOutMillisecs % 1000) * 1000)) * 1000;\r
-\r
- if (time.tv_nsec >= 1000000000)\r
- {\r
- time.tv_nsec -= 1000000000;\r
- time.tv_sec++;\r
- }\r
-\r
- do\r
- {\r
- if (pthread_cond_timedwait (&condition, &mutex, &time) == ETIMEDOUT)\r
- {\r
- pthread_mutex_unlock (&mutex);\r
- return false;\r
- }\r
- }\r
- while (! triggered);\r
- }\r
- }\r
-\r
- if (! manualReset)\r
- triggered = false;\r
-\r
- pthread_mutex_unlock (&mutex);\r
- return true;\r
-}\r
-\r
-void WaitableEvent::signal() const noexcept\r
-{\r
- pthread_mutex_lock (&mutex);\r
-\r
- if (! triggered)\r
- {\r
- triggered = true;\r
- pthread_cond_broadcast (&condition);\r
- }\r
-\r
- pthread_mutex_unlock (&mutex);\r
-}\r
-\r
-void WaitableEvent::reset() const noexcept\r
-{\r
- pthread_mutex_lock (&mutex);\r
- triggered = false;\r
- pthread_mutex_unlock (&mutex);\r
-}\r
-\r
//==============================================================================\r
void JUCE_CALLTYPE Thread::sleep (int millisecs)\r
{\r
if (numBytesRead > 0 || feof (readHandle))\r
return numBytesRead;\r
\r
- // signal occured during fread() so try again\r
+ // signal occurred during fread() so try again\r
if (ferror (readHandle) && errno == EINTR)\r
continue;\r
\r
hasSSE2 = (info[3] & (1 << 26)) != 0;\r
hasSSE3 = (info[2] & (1 << 0)) != 0;\r
hasAVX = (info[2] & (1 << 28)) != 0;\r
+ hasFMA3 = (info[2] & (1 << 12)) != 0;\r
hasSSSE3 = (info[2] & (1 << 9)) != 0;\r
hasSSE41 = (info[2] & (1 << 19)) != 0;\r
hasSSE42 = (info[2] & (1 << 20)) != 0;\r
has3DNow = (info[1] & (1 << 31)) != 0;\r
\r
+ callCPUID (info, 0x80000001);\r
+ hasFMA4 = (info[2] & (1 << 16)) != 0;\r
+\r
callCPUID (info, 7);\r
\r
hasAVX2 = (info[1] & (1 << 5)) != 0;\r
#endif\r
\r
//==============================================================================\r
-RTL_OSVERSIONINFOW getWindowsVersionInfo()\r
-{\r
- RTL_OSVERSIONINFOW versionInfo = { 0 };\r
-\r
- if (auto* moduleHandle = ::GetModuleHandleW (L"ntdll.dll"))\r
- {\r
- using RtlGetVersion = LONG (WINAPI*) (PRTL_OSVERSIONINFOW);\r
-\r
- if (auto* rtlGetVersion = (RtlGetVersion) ::GetProcAddress (moduleHandle, "RtlGetVersion"))\r
- {\r
- versionInfo.dwOSVersionInfoSize = sizeof (versionInfo);\r
- LONG STATUS_SUCCESS = 0;\r
-\r
- if (rtlGetVersion (&versionInfo) != STATUS_SUCCESS)\r
- versionInfo = { 0 };\r
- }\r
- }\r
-\r
- return versionInfo;\r
-}\r
+#if JUCE_MINGW\r
+ static uint32 getWindowsVersion()\r
+ {\r
+ auto filename = _T("kernel32.dll");\r
+ DWORD handle = 0;\r
+\r
+ if (auto size = GetFileVersionInfoSize (filename, &handle))\r
+ {\r
+ HeapBlock<char> data (size);\r
+\r
+ if (GetFileVersionInfo (filename, handle, size, data))\r
+ {\r
+ VS_FIXEDFILEINFO* info = nullptr;\r
+ UINT verSize = 0;\r
+\r
+ if (VerQueryValue (data, (LPCTSTR) _T("\\"), (void**) &info, &verSize))\r
+ if (size > 0 && info != nullptr && info->dwSignature == 0xfeef04bd)\r
+ return (uint32) info->dwFileVersionMS;\r
+ }\r
+ }\r
+\r
+ return 0;\r
+ }\r
+#else\r
+ RTL_OSVERSIONINFOW getWindowsVersionInfo()\r
+ {\r
+ RTL_OSVERSIONINFOW versionInfo = { 0 };\r
+\r
+ if (auto* moduleHandle = ::GetModuleHandleW (L"ntdll.dll"))\r
+ {\r
+ using RtlGetVersion = LONG (WINAPI*) (PRTL_OSVERSIONINFOW);\r
+\r
+ if (auto* rtlGetVersion = (RtlGetVersion) ::GetProcAddress (moduleHandle, "RtlGetVersion"))\r
+ {\r
+ versionInfo.dwOSVersionInfoSize = sizeof (versionInfo);\r
+ LONG STATUS_SUCCESS = 0;\r
+\r
+ if (rtlGetVersion (&versionInfo) != STATUS_SUCCESS)\r
+ versionInfo = { 0 };\r
+ }\r
+ }\r
+\r
+ return versionInfo;\r
+ }\r
+#endif\r
\r
SystemStats::OperatingSystemType SystemStats::getOperatingSystemType()\r
{\r
+ #if JUCE_MINGW\r
+ auto v = getWindowsVersion();\r
+ auto major = (v >> 16) & 0xff;\r
+ auto minor = (v >> 0) & 0xff;\r
+ #else\r
auto versionInfo = getWindowsVersionInfo();\r
auto major = versionInfo.dwMajorVersion;\r
auto minor = versionInfo.dwMinorVersion;\r
+ #endif\r
\r
jassert (major <= 10); // need to add support for new version!\r
\r
void CriticalSection::exit() const noexcept { LeaveCriticalSection ((CRITICAL_SECTION*) lock); }\r
\r
\r
-//==============================================================================\r
-WaitableEvent::WaitableEvent (const bool manualReset) noexcept\r
- : handle (CreateEvent (0, manualReset ? TRUE : FALSE, FALSE, 0)) {}\r
-\r
-WaitableEvent::~WaitableEvent() noexcept { CloseHandle (handle); }\r
-\r
-void WaitableEvent::signal() const noexcept { SetEvent (handle); }\r
-void WaitableEvent::reset() const noexcept { ResetEvent (handle); }\r
-\r
-bool WaitableEvent::wait (const int timeOutMs) const noexcept\r
-{\r
- return WaitForSingleObject (handle, (DWORD) timeOutMs) == WAIT_OBJECT_0;\r
-}\r
-\r
//==============================================================================\r
void JUCE_API juce_threadEntryPoint (void*);\r
\r
currentModuleHandle = newHandle;\r
}\r
\r
-void JUCE_CALLTYPE Process::raisePrivilege()\r
-{\r
- jassertfalse; // xxx not implemented\r
-}\r
-\r
-void JUCE_CALLTYPE Process::lowerPrivilege()\r
-{\r
- jassertfalse; // xxx not implemented\r
-}\r
+void JUCE_CALLTYPE Process::raisePrivilege() {}\r
+void JUCE_CALLTYPE Process::lowerPrivilege() {}\r
\r
void JUCE_CALLTYPE Process::terminate()\r
{\r
using juce_socklen_t = int;\r
using juce_recvsend_size_t = int;\r
using SocketHandle = SOCKET;\r
- #if ! JUCE_MINGW\r
- using pollfd = WSAPOLLFD;\r
- #endif\r
static const SocketHandle invalidSocket = INVALID_SOCKET;\r
#elif JUCE_ANDROID\r
using juce_socklen_t = socklen_t;\r
if (! lock.isLocked())\r
return -1;\r
\r
+ auto hasErrorOccurred = [&handle] () -> bool\r
+ {\r
+ auto h = handle.load();\r
+\r
+ if (h == invalidSocket)\r
+ return true;\r
+\r
+ int opt;\r
+ juce_socklen_t len = sizeof (opt);\r
+\r
+ if (getsockopt (h, SOL_SOCKET, SO_ERROR, (char*) &opt, &len) < 0 || opt != 0)\r
+ return true;\r
+\r
+ return false;\r
+ };\r
+\r
auto h = handle.load();\r
\r
- #if JUCE_MINGW\r
+ #if JUCE_WINDOWS || JUCE_MINGW\r
struct timeval timeout;\r
struct timeval* timeoutp;\r
\r
FD_ZERO (&wset);\r
FD_SET (h, &wset);\r
\r
- fd_set* const prset = forReading ? &rset : nullptr;\r
- fd_set* const pwset = forReading ? nullptr : &wset;\r
+ fd_set* prset = forReading ? &rset : nullptr;\r
+ fd_set* pwset = forReading ? nullptr : &wset;\r
\r
- if (select ((int) h + 1, prset, pwset, 0, timeoutp) < 0)\r
+ // NB - need to use select() here as WSAPoll is broken on Windows\r
+ if (select ((int) h + 1, prset, pwset, nullptr, timeoutp) < 0 || hasErrorOccurred())\r
return -1;\r
- #else\r
+\r
+ return FD_ISSET (h, forReading ? &rset : &wset) ? 1 : 0;\r
+ #else\r
short eventsFlag = (forReading ? POLLIN : POLLOUT);\r
pollfd pfd { (SocketHandle) h, eventsFlag, 0 };\r
\r
\r
for (;;)\r
{\r
- #if JUCE_WINDOWS\r
- result = WSAPoll (&pfd, 1, timeoutMsecs);\r
- #else\r
result = poll (&pfd, 1, timeoutMsecs);\r
- #endif\r
\r
- if (result >= 0\r
- #if JUCE_WINDOWS\r
- || result == SOCKET_ERROR\r
- #else\r
- || errno != EINTR\r
- #endif\r
- )\r
- {\r
+ if (result >= 0 || errno != EINTR)\r
break;\r
- }\r
}\r
\r
- if (result < 0)\r
- return -1;\r
- #endif\r
-\r
- // we are closing\r
- if (handle.load() < 0)\r
+ if (result < 0 || hasErrorOccurred())\r
return -1;\r
\r
- {\r
- int opt;\r
- juce_socklen_t len = sizeof (opt);\r
-\r
- if (getsockopt (h, SOL_SOCKET, SO_ERROR, (char*) &opt, &len) < 0\r
- || opt != 0)\r
- return -1;\r
- }\r
-\r
- #if JUCE_MINGW\r
- return FD_ISSET (h, forReading ? &rset : &wset) ? 1 : 0;\r
- #else\r
return (pfd.revents & eventsFlag) != 0;\r
- #endif\r
+ #endif\r
}\r
\r
static addrinfo* getAddressInfo (bool isDatagram, const String& hostName, int portNumber)\r
break;\r
}\r
\r
- fileStream->flush();\r
+ fileStream.reset();\r
\r
if (threadShouldExit() || stream->isError())\r
error = true;\r
}\r
\r
//==============================================================================\r
- const std::unique_ptr<FileOutputStream> fileStream;\r
+ std::unique_ptr<FileOutputStream> fileStream;\r
const std::unique_ptr<WebInputStream> stream;\r
const size_t bufferSize;\r
HeapBlock<char> buffer;\r
The position is an absolute number of bytes from the stream's start.\r
\r
For a WebInputStream, this method will fail if wantedPos is smaller\r
- than the curent position. If wantedPos is greater than the current\r
+ than the current position. If wantedPos is greater than the current\r
position, then calling setPosition is the same as calling read, i.e.\r
the skipped data will still be downloaded, although skipped bytes will\r
- be discarded immedietely.\r
+ be discarded immediately.\r
\r
@returns true if the stream manages to reposition itself correctly\r
@see getPosition\r
\r
Note that the destination block will always be larger than the amount of data\r
that has been written to the stream, because the MemoryOutputStream keeps some\r
- spare capactity at its end. To trim the block's size down to fit the actual\r
+ spare capacity at its end. To trim the block's size down to fit the actual\r
data, call flush(), or delete the MemoryOutputStream.\r
\r
@param memoryBlockToWriteTo the block into which new data will be written.\r
*/\r
#define JUCE_MAJOR_VERSION 5\r
#define JUCE_MINOR_VERSION 4\r
-#define JUCE_BUILDNUMBER 5\r
+#define JUCE_BUILDNUMBER 6\r
\r
/** Current JUCE version number.\r
\r
#include <sstream>\r
#include <iomanip>\r
#include <map>\r
+#include <cstddef>\r
+#include <unordered_set>\r
+#include <mutex>\r
+#include <condition_variable>\r
+#include <queue>\r
\r
//==============================================================================\r
#include "juce_CompilerSupport.h"\r
#undef minor\r
#undef KeyPress\r
\r
-// Include a replacement for std::function\r
-#if JUCE_PROJUCER_LIVE_BUILD\r
- #include "../misc/juce_StdFunctionCompat.h"\r
-#endif\r
-\r
//==============================================================================\r
// DLL building settings on Windows\r
#if JUCE_MSVC\r
\r
int numLogicalCPUs = 0, numPhysicalCPUs = 0;\r
\r
- bool hasMMX = false, hasSSE = false, hasSSE2 = false, hasSSE3 = false,\r
- has3DNow = false, hasSSSE3 = false, hasSSE41 = false,\r
- hasSSE42 = false, hasAVX = false, hasAVX2 = false,\r
+ bool hasMMX = false, hasSSE = false, hasSSE2 = false, hasSSE3 = false,\r
+ has3DNow = false, hasFMA3 = false, hasFMA4 = false, hasSSSE3 = false,\r
+ hasSSE41 = false, hasSSE42 = false, hasAVX = false, hasAVX2 = false,\r
hasAVX512F = false, hasAVX512BW = false, hasAVX512CD = false,\r
hasAVX512DQ = false, hasAVX512ER = false, hasAVX512IFMA = false,\r
hasAVX512PF = false, hasAVX512VBMI = false, hasAVX512VL = false,\r
int SystemStats::getNumPhysicalCpus() noexcept { return getCPUInformation().numPhysicalCPUs; }\r
bool SystemStats::hasMMX() noexcept { return getCPUInformation().hasMMX; }\r
bool SystemStats::has3DNow() noexcept { return getCPUInformation().has3DNow; }\r
+bool SystemStats::hasFMA3() noexcept { return getCPUInformation().hasFMA3; }\r
+bool SystemStats::hasFMA4() noexcept { return getCPUInformation().hasFMA4; }\r
bool SystemStats::hasSSE() noexcept { return getCPUInformation().hasSSE; }\r
bool SystemStats::hasSSE2() noexcept { return getCPUInformation().hasSSE2; }\r
bool SystemStats::hasSSE3() noexcept { return getCPUInformation().hasSSE3; }\r
\r
static bool hasMMX() noexcept; /**< Returns true if Intel MMX instructions are available. */\r
static bool has3DNow() noexcept; /**< Returns true if AMD 3DNOW instructions are available. */\r
+ static bool hasFMA3() noexcept; /**< Returns true if AMD FMA3 instructions are available. */\r
+ static bool hasFMA4() noexcept; /**< Returns true if AMD FMA4 instructions are available. */\r
static bool hasSSE() noexcept; /**< Returns true if Intel SSE instructions are available. */\r
static bool hasSSE2() noexcept; /**< Returns true if Intel SSE2 instructions are available. */\r
static bool hasSSE3() noexcept; /**< Returns true if Intel SSE3 instructions are available. */\r
countries: fr be mc ch lu\r
@endcode\r
\r
- The country codes are supposed to be 2-character ISO complient codes.\r
+ The country codes are supposed to be 2-character ISO compliant codes.\r
*/\r
const StringArray& getCountryCodes() const { return countryCodes; }\r
\r
static void JUCE_CALLTYPE setCurrentModuleInstanceHandle (void* newHandle) noexcept;\r
#endif\r
\r
- #if JUCE_MAC || DOXYGEN\r
+ #if (JUCE_MAC && JUCE_MODULE_AVAILABLE_juce_gui_basics) || DOXYGEN\r
//==============================================================================\r
/** OSX ONLY - Shows or hides the OSX dock icon for this app. */\r
static void setDockIconVisible (bool isVisible);\r
void ReadWriteLock::enterRead() const noexcept\r
{\r
while (! tryEnterRead())\r
- waitEvent.wait (100);\r
+ readWaitEvent.wait (100);\r
}\r
\r
bool ReadWriteLock::tryEnterRead() const noexcept\r
{\r
- const Thread::ThreadID threadId = Thread::getCurrentThreadId();\r
+ auto threadId = Thread::getCurrentThreadId();\r
\r
const SpinLock::ScopedLockType sl (accessLock);\r
\r
- for (int i = 0; i < readerThreads.size(); ++i)\r
+ for (auto& readerThread : readerThreads)\r
{\r
- ThreadRecursionCount& trc = readerThreads.getReference(i);\r
-\r
- if (trc.threadID == threadId)\r
+ if (readerThread.threadID == threadId)\r
{\r
- trc.count++;\r
+ readerThread.count++;\r
return true;\r
}\r
}\r
if (numWriters + numWaitingWriters == 0\r
|| (threadId == writerThreadId && numWriters > 0))\r
{\r
- ThreadRecursionCount trc = { threadId, 1 };\r
- readerThreads.add (trc);\r
+ readerThreads.add ({ threadId, 1 });\r
return true;\r
}\r
\r
\r
void ReadWriteLock::exitRead() const noexcept\r
{\r
- const Thread::ThreadID threadId = Thread::getCurrentThreadId();\r
+ auto threadId = Thread::getCurrentThreadId();\r
const SpinLock::ScopedLockType sl (accessLock);\r
\r
for (int i = 0; i < readerThreads.size(); ++i)\r
{\r
- ThreadRecursionCount& trc = readerThreads.getReference(i);\r
+ auto& readerThread = readerThreads.getReference (i);\r
\r
- if (trc.threadID == threadId)\r
+ if (readerThread.threadID == threadId)\r
{\r
- if (--(trc.count) == 0)\r
+ if (--(readerThread.count) == 0)\r
{\r
readerThreads.remove (i);\r
- waitEvent.signal();\r
+\r
+ readWaitEvent.signal();\r
+ writeWaitEvent.signal();\r
}\r
\r
return;\r
//==============================================================================\r
void ReadWriteLock::enterWrite() const noexcept\r
{\r
- const Thread::ThreadID threadId = Thread::getCurrentThreadId();\r
+ auto threadId = Thread::getCurrentThreadId();\r
const SpinLock::ScopedLockType sl (accessLock);\r
\r
while (! tryEnterWriteInternal (threadId))\r
{\r
++numWaitingWriters;\r
accessLock.exit();\r
- waitEvent.wait (100);\r
+ writeWaitEvent.wait (100);\r
accessLock.enter();\r
--numWaitingWriters;\r
}\r
{\r
if (readerThreads.size() + numWriters == 0\r
|| threadId == writerThreadId\r
- || (readerThreads.size() == 1 && readerThreads.getReference(0).threadID == threadId))\r
+ || (readerThreads.size() == 1 && readerThreads.getReference (0).threadID == threadId))\r
{\r
writerThreadId = threadId;\r
++numWriters;\r
if (--numWriters == 0)\r
{\r
writerThreadId = {};\r
- waitEvent.signal();\r
+\r
+ readWaitEvent.signal();\r
+ writeWaitEvent.signal();\r
}\r
}\r
\r
private:\r
//==============================================================================\r
SpinLock accessLock;\r
- WaitableEvent waitEvent;\r
+ WaitableEvent readWaitEvent, writeWaitEvent;\r
mutable int numWaitingWriters = 0, numWriters = 0;\r
mutable Thread::ThreadID writerThreadId = {};\r
\r
again when a thread is free. */\r
};\r
\r
- /** Peforms the actual work that this job needs to do.\r
+ /** Performs the actual work that this job needs to do.\r
\r
Your subclass must implement this method, in which is does its work.\r
\r
@returns Your method should return the number of milliseconds which it would like to wait before being called\r
again. Returning 0 will make the thread call again as soon as possible (after possibly servicing\r
other busy clients). If you return a value below zero, your client will be removed from the list of clients,\r
- and won't be called again. The value you specify isn't a guaranteee, and is only used as a hint by the\r
+ and won't be called again. The value you specify isn't a guarantee, and is only used as a hint by the\r
thread - the actual time before the next callback may be more or less than specified.\r
You can force the TimeSliceThread to wake up and poll again immediately by calling its notify() method.\r
*/\r
--- /dev/null
+/*\r
+ ==============================================================================\r
+\r
+ This file is part of the JUCE library.\r
+ Copyright (c) 2017 - ROLI Ltd.\r
+\r
+ JUCE is an open source library subject to commercial or open-source\r
+ licensing.\r
+\r
+ The code included in this file is provided under the terms of the ISC license\r
+ http://www.isc.org/downloads/software-support-policy/isc-license. Permission\r
+ To use, copy, modify, and/or distribute this software for any purpose with or\r
+ without fee is hereby granted provided that the above copyright notice and\r
+ this permission notice appear in all copies.\r
+\r
+ JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER\r
+ EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE\r
+ DISCLAIMED.\r
+\r
+ ==============================================================================\r
+*/\r
+\r
+namespace juce\r
+{\r
+\r
+WaitableEvent::WaitableEvent (bool manualReset) noexcept\r
+ : useManualReset (manualReset)\r
+{\r
+}\r
+\r
+bool WaitableEvent::wait (int timeOutMilliseconds) const\r
+{\r
+ std::unique_lock<std::mutex> lock (mutex);\r
+\r
+ if (! triggered)\r
+ {\r
+ if (timeOutMilliseconds < 0)\r
+ {\r
+ condition.wait (lock, [this] { return triggered == true; });\r
+ }\r
+ else\r
+ {\r
+ if (! condition.wait_for (lock, std::chrono::milliseconds (timeOutMilliseconds),\r
+ [this] { return triggered == true; }))\r
+ {\r
+ return false;\r
+ }\r
+ }\r
+ }\r
+\r
+ if (! useManualReset)\r
+ reset();\r
+\r
+ return true;\r
+}\r
+\r
+void WaitableEvent::signal() const\r
+{\r
+ std::unique_lock<std::mutex> lock (mutex);\r
+\r
+ triggered = true;\r
+ condition.notify_all();\r
+}\r
+\r
+void WaitableEvent::reset() const\r
+{\r
+ triggered = false;\r
+}\r
+\r
+} // namespace juce\r
*/\r
explicit WaitableEvent (bool manualReset = false) noexcept;\r
\r
- /** Destructor.\r
-\r
- If other threads are waiting on this object when it gets deleted, this\r
- can cause nasty errors, so be careful!\r
- */\r
- ~WaitableEvent() noexcept;\r
-\r
//==============================================================================\r
/** Suspends the calling thread until the event has been signalled.\r
\r
@returns true if the object has been signalled, false if the timeout expires first.\r
@see signal, reset\r
*/\r
- bool wait (int timeOutMilliseconds = -1) const noexcept;\r
+ bool wait (int timeOutMilliseconds = -1) const;\r
\r
- //==============================================================================\r
/** Wakes up any threads that are currently waiting on this object.\r
\r
If signal() is called when nothing is waiting, the next thread to call wait()\r
\r
@see wait, reset\r
*/\r
- void signal() const noexcept;\r
+ void signal() const;\r
\r
- //==============================================================================\r
/** Resets the event to an unsignalled state.\r
If it's not already signalled, this does nothing.\r
*/\r
- void reset() const noexcept;\r
-\r
+ void reset() const;\r
\r
private:\r
//==============================================================================\r
- #if JUCE_WINDOWS\r
- void* handle;\r
- #else\r
- mutable pthread_cond_t condition;\r
- mutable pthread_mutex_t mutex;\r
- mutable bool triggered, manualReset;\r
- #endif\r
+ bool useManualReset;\r
+\r
+ mutable std::mutex mutex;\r
+ mutable std::condition_variable condition;\r
+ mutable std::atomic<bool> triggered { false };\r
\r
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (WaitableEvent)\r
};\r
entry.uncompressedSize = (int64) readUnalignedLittleEndianInt (buffer + 24);\r
streamOffset = (int64) readUnalignedLittleEndianInt (buffer + 42);\r
\r
- auto externalFileAttributes = (int32) readUnalignedLittleEndianInt (buffer + 38);\r
- auto fileType = (externalFileAttributes >> 28) & 0xf;\r
-\r
+ entry.externalFileAttributes = readUnalignedLittleEndianInt (buffer + 38);\r
+ auto fileType = (entry.externalFileAttributes >> 28) & 0xf;\r
entry.isSymbolicLink = (fileType == 0xA);\r
+\r
entry.filename = String::fromUTF8 (buffer + 46, fileNameLen);\r
}\r
\r
\r
/** True if the zip entry is a symbolic link. */\r
bool isSymbolicLink;\r
+\r
+ /** Platform specific data. Depending on how the zip file was created this\r
+ may contain macOS and Linux file types, permissions and\r
+ setuid/setgid/sticky bits.\r
+ */\r
+ uint32 externalFileAttributes;\r
};\r
\r
//==============================================================================\r
@param buffer The message that should be encrypted. See bufferSize on size\r
requirements!\r
@param sizeOfMsg The size of the message that should be encrypted in bytes\r
- @param bufferSize The size of the buffer in bytes. To accommodate the encypted\r
+ @param bufferSize The size of the buffer in bytes. To accommodate the encrypted\r
data, the buffer must be larger than the message: the size of\r
the buffer needs to be equal or greater than the size of the\r
- message in bytes rounded to the next integer which is divisable\r
- by eight. If the message size in bytes is already divisable by eight\r
+ message in bytes rounded to the next integer which is divisible\r
+ by eight. If the message size in bytes is already divisible by eight\r
then you need to add eight bytes to the buffer size. If in doubt\r
simply use bufferSize = sizeOfMsg + 8.\r
\r
==============================================================================\r
*/\r
\r
+\r
/*******************************************************************************\r
The block below describes the properties of this module, and is read by\r
the Projucer to automatically generate project code that uses it.\r
\r
BEGIN_JUCE_MODULE_DECLARATION\r
\r
- ID: juce_cryptography\r
- vendor: juce\r
- version: 5.4.5\r
- name: JUCE cryptography classes\r
- description: Classes for various basic cryptography functions, including RSA, Blowfish, MD5, SHA, etc.\r
- website: http://www.juce.com/juce\r
- license: GPL/Commercial\r
+ ID: juce_cryptography\r
+ vendor: juce\r
+ version: 5.4.6\r
+ name: JUCE cryptography classes\r
+ description: Classes for various basic cryptography functions, including RSA, Blowfish, MD5, SHA, etc.\r
+ website: http://www.juce.com/juce\r
+ license: GPL/Commercial\r
\r
- dependencies: juce_core\r
+ dependencies: juce_core\r
\r
END_JUCE_MODULE_DECLARATION\r
\r
==============================================================================\r
*/\r
\r
+\r
/*******************************************************************************\r
The block below describes the properties of this module, and is read by\r
the Projucer to automatically generate project code that uses it.\r
\r
BEGIN_JUCE_MODULE_DECLARATION\r
\r
- ID: juce_data_structures\r
- vendor: juce\r
- version: 5.4.5\r
- name: JUCE data model helper classes\r
- description: Classes for undo/redo management, and smart data structures.\r
- website: http://www.juce.com/juce\r
- license: GPL/Commercial\r
+ ID: juce_data_structures\r
+ vendor: juce\r
+ version: 5.4.6\r
+ name: JUCE data model helper classes\r
+ description: Classes for undo/redo management, and smart data structures.\r
+ website: http://www.juce.com/juce\r
+ license: GPL/Commercial\r
\r
- dependencies: juce_events\r
+ dependencies: juce_events\r
\r
END_JUCE_MODULE_DECLARATION\r
\r
will correspond to the order in which the property was added, or that it will remain\r
constant when other properties are added or removed.\r
\r
- Listeners can be added to a ValueTree to be told when properies change and when\r
+ Listeners can be added to a ValueTree to be told when properties change and when\r
sub-trees are added or removed.\r
\r
@see var, XmlElement\r
return AudioBlock (channels + channel, 1, startSample, numSamples);\r
}\r
\r
- /** Returns a subset of continguous channels\r
+ /** Returns a subset of contiguous channels\r
@param channelStart First channel of the subset\r
@param numChannelsToUse Count of channels in the subset\r
*/\r
const AudioBlock& clear() const noexcept { clearInternal(); return *this; }\r
\r
/** Fills the memory referenced by this AudioBlock with value. */\r
- AudioBlock& JUCE_VECTOR_CALLTYPE fill (SampleType value) noexcept { fillInternal (value); return *this; }\r
- const AudioBlock& JUCE_VECTOR_CALLTYPE fill (SampleType value) const noexcept { fillInternal (value); return *this; }\r
+ AudioBlock& JUCE_VECTOR_CALLTYPE fill (NumericType value) noexcept { fillInternal (value); return *this; }\r
+ const AudioBlock& JUCE_VECTOR_CALLTYPE fill (NumericType value) const noexcept { fillInternal (value); return *this; }\r
\r
/** Copies the values in src to this block. */\r
template <typename OtherSampleType>\r
template <typename OtherSampleType>\r
const AudioBlock& copyFrom (const AudioBlock<OtherSampleType>& src) const noexcept { copyFromInternal (src); return *this; }\r
\r
- /** Copy the values from a JUCE's AudioBuffer to this block.\r
+ /** Copy the values from an AudioBuffer to this block.\r
\r
- All indices and sizes are in the receiver's units, i.e. if SampleType is a\r
+ All indices and sizes are in this AudioBlock's units, i.e. if SampleType is a\r
SIMDRegister then incrementing srcPos by one will increase the sample position\r
in the AudioBuffer's units by a factor of SIMDRegister<SampleType>::SIMDNumElements.\r
*/\r
- template <typename OtherSampleType>\r
- AudioBlock& copyFrom (const AudioBuffer<OtherSampleType>& src,\r
+ template <typename OtherNumericType>\r
+ AudioBlock& copyFrom (const AudioBuffer<OtherNumericType>& src,\r
size_t srcPos = 0, size_t dstPos = 0,\r
size_t numElements = std::numeric_limits<size_t>::max()) { copyFromInternal (src, srcPos, dstPos, numElements); return *this; }\r
- template <typename OtherSampleType>\r
- const AudioBlock& copyFrom (const AudioBuffer<OtherSampleType>& src,\r
+ template <typename OtherNumericType>\r
+ const AudioBlock& copyFrom (const AudioBuffer<OtherNumericType>& src,\r
size_t srcPos = 0, size_t dstPos = 0,\r
size_t numElements = std::numeric_limits<size_t>::max()) const { copyFromInternal (src, srcPos, dstPos, numElements); return *this; }\r
\r
\r
/** Copies the values from this block to an AudioBuffer.\r
\r
- All indices and sizes are in the receiver's units, i.e. if SampleType is a\r
+ All indices and sizes are in this AudioBlock's units, i.e. if SampleType is a\r
SIMDRegister then incrementing dstPos by one will increase the sample position\r
in the AudioBuffer's units by a factor of SIMDRegister<SampleType>::SIMDNumElements.\r
*/\r
for (size_t ch = 0; ch < maxChannels; ++ch)\r
FloatVectorOperations::copy (dst.getWritePointer (static_cast<int> (ch),\r
static_cast<int> (dstPos * sizeFactor)),\r
- getChannelPointer (ch) + srcPos, n);\r
+ getDataPointer (ch) + (srcPos * sizeFactor),\r
+ n);\r
}\r
\r
/** Move memory within this block from the position srcPos to the position dstPos.\r
\r
//==============================================================================\r
/** Adds a fixed value to the elements in this block. */\r
- AudioBlock& JUCE_VECTOR_CALLTYPE add (SampleType value) noexcept { addInternal (value); return *this; }\r
- const AudioBlock& JUCE_VECTOR_CALLTYPE add (SampleType value) const noexcept { addInternal (value); return *this; }\r
+ AudioBlock& JUCE_VECTOR_CALLTYPE add (NumericType value) noexcept { addInternal (value); return *this; }\r
+ const AudioBlock& JUCE_VECTOR_CALLTYPE add (NumericType value) const noexcept { addInternal (value); return *this; }\r
\r
/** Adds the elements in the src block to the elements in this block. */\r
template <typename OtherSampleType>\r
\r
/** Adds a fixed value to each source value and replaces the contents of this block. */\r
template <typename OtherSampleType>\r
- AudioBlock& JUCE_VECTOR_CALLTYPE replaceWithSumOf (AudioBlock<OtherSampleType> src, SampleType value) noexcept { replaceWithSumOfInternal (src, value); return *this; }\r
+ AudioBlock& JUCE_VECTOR_CALLTYPE replaceWithSumOf (AudioBlock<OtherSampleType> src, NumericType value) noexcept { replaceWithSumOfInternal (src, value); return *this; }\r
template <typename OtherSampleType>\r
- const AudioBlock& JUCE_VECTOR_CALLTYPE replaceWithSumOf (AudioBlock<OtherSampleType> src, SampleType value) const noexcept { replaceWithSumOfInternal (src, value); return *this; }\r
+ const AudioBlock& JUCE_VECTOR_CALLTYPE replaceWithSumOf (AudioBlock<OtherSampleType> src, NumericType value) const noexcept { replaceWithSumOfInternal (src, value); return *this; }\r
\r
/** Adds each source1 value to the corresponding source2 value and replaces the contents of this block. */\r
template <typename Src1SampleType, typename Src2SampleType>\r
\r
//==============================================================================\r
/** Subtracts a fixed value from the elements in this block. */\r
- AudioBlock& JUCE_VECTOR_CALLTYPE subtract (SampleType value) noexcept { subtractInternal (value); return *this; }\r
- const AudioBlock& JUCE_VECTOR_CALLTYPE subtract (SampleType value) const noexcept { subtractInternal (value); return *this; }\r
+ AudioBlock& JUCE_VECTOR_CALLTYPE subtract (NumericType value) noexcept { subtractInternal (value); return *this; }\r
+ const AudioBlock& JUCE_VECTOR_CALLTYPE subtract (NumericType value) const noexcept { subtractInternal (value); return *this; }\r
\r
/** Subtracts the source values from the elements in this block. */\r
template <typename OtherSampleType>\r
\r
/** Subtracts a fixed value from each source value and replaces the contents of this block. */\r
template <typename OtherSampleType>\r
- AudioBlock& JUCE_VECTOR_CALLTYPE replaceWithDifferenceOf (AudioBlock<OtherSampleType> src, SampleType value) noexcept { replaceWithDifferenceOfInternal (src, value); return *this; }\r
+ AudioBlock& JUCE_VECTOR_CALLTYPE replaceWithDifferenceOf (AudioBlock<OtherSampleType> src, NumericType value) noexcept { replaceWithDifferenceOfInternal (src, value); return *this; }\r
template <typename OtherSampleType>\r
- const AudioBlock& JUCE_VECTOR_CALLTYPE replaceWithDifferenceOf (AudioBlock<OtherSampleType> src, SampleType value) const noexcept { replaceWithDifferenceOfInternal (src, value); return *this; }\r
+ const AudioBlock& JUCE_VECTOR_CALLTYPE replaceWithDifferenceOf (AudioBlock<OtherSampleType> src, NumericType value) const noexcept { replaceWithDifferenceOfInternal (src, value); return *this; }\r
\r
/** Subtracts each source2 value from the corresponding source1 value and replaces the contents of this block. */\r
template <typename Src1SampleType, typename Src2SampleType>\r
\r
//==============================================================================\r
/** Multiplies the elements in this block by a fixed value. */\r
- AudioBlock& JUCE_VECTOR_CALLTYPE multiplyBy (SampleType value) noexcept { multiplyByInternal (value); return *this; }\r
- const AudioBlock& JUCE_VECTOR_CALLTYPE multiplyBy (SampleType value) const noexcept { multiplyByInternal (value); return *this; }\r
+ AudioBlock& JUCE_VECTOR_CALLTYPE multiplyBy (NumericType value) noexcept { multiplyByInternal (value); return *this; }\r
+ const AudioBlock& JUCE_VECTOR_CALLTYPE multiplyBy (NumericType value) const noexcept { multiplyByInternal (value); return *this; }\r
\r
/** Multiplies the elements in this block by the elements in the src block */\r
template <typename OtherSampleType>\r
\r
/** Replaces the elements in this block with the product of the elements in the source src block and a fixed value. */\r
template <typename OtherSampleType>\r
- AudioBlock& JUCE_VECTOR_CALLTYPE replaceWithProductOf (AudioBlock<OtherSampleType> src, SampleType value) noexcept { replaceWithProductOfInternal (src, value); return *this; }\r
+ AudioBlock& JUCE_VECTOR_CALLTYPE replaceWithProductOf (AudioBlock<OtherSampleType> src, NumericType value) noexcept { replaceWithProductOfInternal (src, value); return *this; }\r
template <typename OtherSampleType>\r
- const AudioBlock& JUCE_VECTOR_CALLTYPE replaceWithProductOf (AudioBlock<OtherSampleType> src, SampleType value) const noexcept { replaceWithProductOfInternal (src, value); return *this; }\r
+ const AudioBlock& JUCE_VECTOR_CALLTYPE replaceWithProductOf (AudioBlock<OtherSampleType> src, NumericType value) const noexcept { replaceWithProductOfInternal (src, value); return *this; }\r
\r
/** Replaces the elements in this block with the product of the elements in the src1 and scr2 blocks. */\r
template <typename Src1SampleType, typename Src2SampleType>\r
//==============================================================================\r
/** Multiplies each value in src by a fixed value and adds the result to this block. */\r
template <typename OtherSampleType>\r
- AudioBlock& JUCE_VECTOR_CALLTYPE addProductOf (AudioBlock<OtherSampleType> src, SampleType factor) noexcept { addProductOfInternal (src, factor); return *this; }\r
+ AudioBlock& JUCE_VECTOR_CALLTYPE addProductOf (AudioBlock<OtherSampleType> src, NumericType factor) noexcept { addProductOfInternal (src, factor); return *this; }\r
template <typename OtherSampleType>\r
- const AudioBlock& JUCE_VECTOR_CALLTYPE addProductOf (AudioBlock<OtherSampleType> src, SampleType factor) const noexcept { addProductOfInternal (src, factor); return *this; }\r
+ const AudioBlock& JUCE_VECTOR_CALLTYPE addProductOf (AudioBlock<OtherSampleType> src, NumericType factor) const noexcept { addProductOfInternal (src, factor); return *this; }\r
\r
/** Multiplies each value in srcA with the corresponding value in srcB and adds the result to this block. */\r
template <typename Src1SampleType, typename Src2SampleType>\r
return {};\r
\r
auto n = static_cast<int> (numSamples * sizeFactor);\r
- auto minmax = FloatVectorOperations::findMinAndMax (getChannelPointer (0), n);\r
+ auto minmax = FloatVectorOperations::findMinAndMax (getDataPointer (0), n);\r
\r
for (size_t ch = 1; ch < numChannels; ++ch)\r
- minmax = minmax.getUnionWith (FloatVectorOperations::findMinAndMax (getChannelPointer (ch), n));\r
+ minmax = minmax.getUnionWith (FloatVectorOperations::findMinAndMax (getDataPointer (ch), n));\r
\r
return minmax;\r
}\r
\r
//==============================================================================\r
// Convenient operator wrappers.\r
- AudioBlock& JUCE_VECTOR_CALLTYPE operator+= (SampleType value) noexcept { return add (value); }\r
- const AudioBlock& JUCE_VECTOR_CALLTYPE operator+= (SampleType value) const noexcept { return add (value); }\r
+ AudioBlock& JUCE_VECTOR_CALLTYPE operator+= (NumericType value) noexcept { return add (value); }\r
+ const AudioBlock& JUCE_VECTOR_CALLTYPE operator+= (NumericType value) const noexcept { return add (value); }\r
\r
AudioBlock& operator+= (AudioBlock src) noexcept { return add (src); }\r
const AudioBlock& operator+= (AudioBlock src) const noexcept { return add (src); }\r
\r
- AudioBlock& JUCE_VECTOR_CALLTYPE operator-= (SampleType value) noexcept { return subtract (value); }\r
- const AudioBlock& JUCE_VECTOR_CALLTYPE operator-= (SampleType value) const noexcept { return subtract (value); }\r
+ AudioBlock& JUCE_VECTOR_CALLTYPE operator-= (NumericType value) noexcept { return subtract (value); }\r
+ const AudioBlock& JUCE_VECTOR_CALLTYPE operator-= (NumericType value) const noexcept { return subtract (value); }\r
\r
AudioBlock& operator-= (AudioBlock src) noexcept { return subtract (src); }\r
const AudioBlock& operator-= (AudioBlock src) const noexcept { return subtract (src); }\r
\r
- AudioBlock& JUCE_VECTOR_CALLTYPE operator*= (SampleType value) noexcept { return multiplyBy (value); }\r
- const AudioBlock& JUCE_VECTOR_CALLTYPE operator*= (SampleType value) const noexcept { return multiplyBy (value); }\r
+ AudioBlock& JUCE_VECTOR_CALLTYPE operator*= (NumericType value) noexcept { return multiplyBy (value); }\r
+ const AudioBlock& JUCE_VECTOR_CALLTYPE operator*= (NumericType value) const noexcept { return multiplyBy (value); }\r
\r
AudioBlock& operator*= (AudioBlock src) noexcept { return multiplyBy (src); }\r
const AudioBlock& operator*= (AudioBlock src) const noexcept { return multiplyBy (src); }\r
}\r
\r
private:\r
+ NumericType* getDataPointer (size_t channel) const noexcept\r
+ {\r
+ return reinterpret_cast<NumericType*> (getChannelPointer (channel));\r
+ }\r
+\r
//==============================================================================\r
void JUCE_VECTOR_CALLTYPE clearInternal() const noexcept\r
{\r
auto n = static_cast<int> (numSamples * sizeFactor);\r
\r
for (size_t ch = 0; ch < numChannels; ++ch)\r
- FloatVectorOperations::clear (getChannelPointer (ch), n);\r
+ FloatVectorOperations::clear (getDataPointer (ch), n);\r
}\r
\r
- void JUCE_VECTOR_CALLTYPE fillInternal (SampleType value) const noexcept\r
+ void JUCE_VECTOR_CALLTYPE fillInternal (NumericType value) const noexcept\r
{\r
auto n = static_cast<int> (numSamples * sizeFactor);\r
\r
for (size_t ch = 0; ch < numChannels; ++ch)\r
- FloatVectorOperations::fill (getChannelPointer (ch), value, n);\r
+ FloatVectorOperations::fill (getDataPointer (ch), value, n);\r
}\r
\r
template <typename OtherSampleType>\r
void copyFromInternal (const AudioBlock<OtherSampleType>& src) const noexcept\r
{\r
auto maxChannels = jmin (src.numChannels, numChannels);\r
- auto n = static_cast<int> (jmin (src.numSamples, numSamples) * sizeFactor);\r
+ auto n = static_cast<int> (jmin (src.numSamples * src.sizeFactor,\r
+ numSamples * sizeFactor));\r
\r
for (size_t ch = 0; ch < maxChannels; ++ch)\r
- FloatVectorOperations::copy (getChannelPointer (ch), src.getChannelPointer (ch), n);\r
+ FloatVectorOperations::copy (getDataPointer (ch), src.getDataPointer (ch), n);\r
}\r
\r
- template <typename OtherSampleType>\r
- void copyFromInternal (const AudioBuffer<OtherSampleType>& src, size_t srcPos, size_t dstPos, size_t numElements) const\r
+ template <typename OtherNumericType>\r
+ void copyFromInternal (const AudioBuffer<OtherNumericType>& src, size_t srcPos, size_t dstPos, size_t numElements) const\r
{\r
auto srclen = static_cast<size_t> (src.getNumSamples()) / sizeFactor;\r
auto n = static_cast<int> (jmin (srclen - srcPos, numSamples - dstPos, numElements) * sizeFactor);\r
auto maxChannels = jmin (static_cast<size_t> (src.getNumChannels()), static_cast<size_t> (numChannels));\r
\r
for (size_t ch = 0; ch < maxChannels; ++ch)\r
- FloatVectorOperations::copy (getChannelPointer (ch) + dstPos,\r
+ FloatVectorOperations::copy (getDataPointer (ch) + (dstPos * sizeFactor),\r
src.getReadPointer (static_cast<int> (ch),\r
static_cast<int> (srcPos * sizeFactor)),\r
n);\r
}\r
\r
//==============================================================================\r
- void JUCE_VECTOR_CALLTYPE addInternal (SampleType value) const noexcept\r
+ void JUCE_VECTOR_CALLTYPE addInternal (NumericType value) const noexcept\r
{\r
auto n = static_cast<int> (numSamples * sizeFactor);\r
\r
for (size_t ch = 0; ch < numChannels; ++ch)\r
- FloatVectorOperations::add (getChannelPointer (ch), value, n);\r
+ FloatVectorOperations::add (getDataPointer (ch), value, n);\r
}\r
\r
template <typename OtherSampleType>\r
auto n = static_cast<int> (jmin (numSamples, src.numSamples) * sizeFactor);\r
\r
for (size_t ch = 0; ch < numChannels; ++ch)\r
- FloatVectorOperations::add (getChannelPointer (ch), src.getChannelPointer (ch), n);\r
+ FloatVectorOperations::add (getDataPointer (ch), src.getDataPointer (ch), n);\r
}\r
\r
template <typename OtherSampleType>\r
- void JUCE_VECTOR_CALLTYPE replaceWithSumOfInternal (AudioBlock<OtherSampleType> src, SampleType value) const noexcept\r
+ void JUCE_VECTOR_CALLTYPE replaceWithSumOfInternal (AudioBlock<OtherSampleType> src, NumericType value) const noexcept\r
{\r
jassert (numChannels == src.numChannels);\r
auto n = static_cast<int> (jmin (numSamples, src.numSamples) * sizeFactor);\r
\r
for (size_t ch = 0; ch < numChannels; ++ch)\r
- FloatVectorOperations::add (getChannelPointer (ch), src.getChannelPointer (ch), value, n);\r
+ FloatVectorOperations::add (getDataPointer (ch), src.getDataPointer (ch), value, n);\r
}\r
\r
template <typename Src1SampleType, typename Src2SampleType>\r
auto n = static_cast<int> (jmin (numSamples, src1.numSamples, src2.numSamples) * sizeFactor);\r
\r
for (size_t ch = 0; ch < numChannels; ++ch)\r
- FloatVectorOperations::add (getChannelPointer (ch), src1.getChannelPointer (ch), src2.getChannelPointer (ch), n);\r
+ FloatVectorOperations::add (getDataPointer (ch), src1.getDataPointer (ch), src2.getDataPointer (ch), n);\r
}\r
\r
//==============================================================================\r
- constexpr void JUCE_VECTOR_CALLTYPE subtractInternal (SampleType value) const noexcept\r
+ constexpr void JUCE_VECTOR_CALLTYPE subtractInternal (NumericType value) const noexcept\r
{\r
- addInternal (value * static_cast<SampleType> (-1.0));\r
+ addInternal (value * static_cast<NumericType> (-1.0));\r
}\r
\r
template <typename OtherSampleType>\r
auto n = static_cast<int> (jmin (numSamples, src.numSamples) * sizeFactor);\r
\r
for (size_t ch = 0; ch < numChannels; ++ch)\r
- FloatVectorOperations::subtract (getChannelPointer (ch), src.getChannelPointer (ch), n);\r
+ FloatVectorOperations::subtract (getDataPointer (ch), src.getDataPointer (ch), n);\r
}\r
\r
template <typename OtherSampleType>\r
- void JUCE_VECTOR_CALLTYPE replaceWithDifferenceOfInternal (AudioBlock<OtherSampleType> src, SampleType value) const noexcept\r
+ void JUCE_VECTOR_CALLTYPE replaceWithDifferenceOfInternal (AudioBlock<OtherSampleType> src, NumericType value) const noexcept\r
{\r
- replaceWithSumOfInternal (src, static_cast<SampleType> (-1.0) * value);\r
+ replaceWithSumOfInternal (src, static_cast<NumericType> (-1.0) * value);\r
}\r
\r
template <typename Src1SampleType, typename Src2SampleType>\r
auto n = static_cast<int> (jmin (numSamples, src1.numSamples, src2.numSamples) * sizeFactor);\r
\r
for (size_t ch = 0; ch < numChannels; ++ch)\r
- FloatVectorOperations::subtract (getChannelPointer (ch), src1.getChannelPointer (ch), src2.getChannelPointer (ch), n);\r
+ FloatVectorOperations::subtract (getDataPointer (ch), src1.getDataPointer (ch), src2.getDataPointer (ch), n);\r
}\r
\r
//==============================================================================\r
- void JUCE_VECTOR_CALLTYPE multiplyByInternal (SampleType value) const noexcept\r
+ void JUCE_VECTOR_CALLTYPE multiplyByInternal (NumericType value) const noexcept\r
{\r
auto n = static_cast<int> (numSamples * sizeFactor);\r
\r
for (size_t ch = 0; ch < numChannels; ++ch)\r
- FloatVectorOperations::multiply (getChannelPointer (ch), value, n);\r
+ FloatVectorOperations::multiply (getDataPointer (ch), value, n);\r
}\r
\r
template <typename OtherSampleType>\r
auto n = static_cast<int> (jmin (numSamples, src.numSamples) * sizeFactor);\r
\r
for (size_t ch = 0; ch < numChannels; ++ch)\r
- FloatVectorOperations::multiply (getChannelPointer (ch), src.getChannelPointer (ch), n);\r
+ FloatVectorOperations::multiply (getDataPointer (ch), src.getDataPointer (ch), n);\r
}\r
\r
template <typename OtherSampleType>\r
- void JUCE_VECTOR_CALLTYPE replaceWithProductOfInternal (AudioBlock<OtherSampleType> src, SampleType value) const noexcept\r
+ void JUCE_VECTOR_CALLTYPE replaceWithProductOfInternal (AudioBlock<OtherSampleType> src, NumericType value) const noexcept\r
{\r
jassert (numChannels == src.numChannels);\r
auto n = static_cast<int> (jmin (numSamples, src.numSamples) * sizeFactor);\r
\r
for (size_t ch = 0; ch < numChannels; ++ch)\r
- FloatVectorOperations::multiply (getChannelPointer (ch), src.getChannelPointer (ch), value, n);\r
+ FloatVectorOperations::multiply (getDataPointer (ch), src.getDataPointer (ch), value, n);\r
}\r
\r
template <typename Src1SampleType, typename Src2SampleType>\r
auto n = static_cast<int> (jmin (numSamples, src1.numSamples, src2.numSamples) * sizeFactor);\r
\r
for (size_t ch = 0; ch < numChannels; ++ch)\r
- FloatVectorOperations::multiply (getChannelPointer (ch), src1.getChannelPointer (ch), src2.getChannelPointer (ch), n);\r
+ FloatVectorOperations::multiply (getDataPointer (ch), src1.getDataPointer (ch), src2.getDataPointer (ch), n);\r
}\r
\r
template <typename SmoothingType>\r
const auto scaler = value.getNextValue();\r
\r
for (size_t ch = 0; ch < numChannels; ++ch)\r
- getChannelPointer (ch)[i] *= scaler;\r
+ getDataPointer (ch)[i] *= scaler;\r
}\r
}\r
}\r
const auto scaler = value.getNextValue();\r
\r
for (size_t ch = 0; ch < numChannels; ++ch)\r
- getChannelPointer (ch)[i] = scaler * src.getChannelPointer (ch)[i];\r
+ getDataPointer (ch)[i] = scaler * src.getChannelPointer (ch)[i];\r
}\r
}\r
}\r
\r
//==============================================================================\r
template <typename OtherSampleType>\r
- void JUCE_VECTOR_CALLTYPE addProductOfInternal (AudioBlock<OtherSampleType> src, SampleType factor) const noexcept\r
+ void JUCE_VECTOR_CALLTYPE addProductOfInternal (AudioBlock<OtherSampleType> src, NumericType factor) const noexcept\r
{\r
jassert (numChannels == src.numChannels);\r
auto n = static_cast<int> (jmin (numSamples, src.numSamples) * sizeFactor);\r
\r
for (size_t ch = 0; ch < numChannels; ++ch)\r
- FloatVectorOperations::addWithMultiply (getChannelPointer (ch), src.getChannelPointer (ch), factor, n);\r
+ FloatVectorOperations::addWithMultiply (getDataPointer (ch), src.getDataPointer (ch), factor, n);\r
}\r
\r
template <typename Src1SampleType, typename Src2SampleType>\r
auto n = static_cast<int> (jmin (numSamples, src1.numSamples, src2.numSamples) * sizeFactor);\r
\r
for (size_t ch = 0; ch < numChannels; ++ch)\r
- FloatVectorOperations::addWithMultiply (getChannelPointer (ch), src1.getChannelPointer (ch), src2.getChannelPointer (ch), n);\r
+ FloatVectorOperations::addWithMultiply (getDataPointer (ch), src1.getDataPointer (ch), src2.getDataPointer (ch), n);\r
}\r
\r
//==============================================================================\r
constexpr void negateInternal() const noexcept\r
{\r
- multiplyByInternal (static_cast<SampleType> (-1.0));\r
+ multiplyByInternal (static_cast<NumericType> (-1.0));\r
}\r
\r
template <typename OtherSampleType>\r
auto n = static_cast<int> (jmin (numSamples, src.numSamples) * sizeFactor);\r
\r
for (size_t ch = 0; ch < numChannels; ++ch)\r
- FloatVectorOperations::negate (getChannelPointer (ch), src.getChannelPointer (ch), n);\r
+ FloatVectorOperations::negate (getDataPointer (ch), src.getDataPointer (ch), n);\r
}\r
\r
template <typename OtherSampleType>\r
auto n = static_cast<int> (jmin (numSamples, src.numSamples) * sizeFactor);\r
\r
for (size_t ch = 0; ch < numChannels; ++ch)\r
- FloatVectorOperations::abs (getChannelPointer (ch), src.getChannelPointer (ch), n);\r
+ FloatVectorOperations::abs (getDataPointer (ch), src.getDataPointer (ch), n);\r
}\r
\r
//==============================================================================\r
auto n = static_cast<int> (jmin (src1.numSamples, src2.numSamples, numSamples) * sizeFactor);\r
\r
for (size_t ch = 0; ch < numChannels; ++ch)\r
- FloatVectorOperations::min (getChannelPointer (ch), src1.getChannelPointer (ch), src2.getChannelPointer (ch), n);\r
+ FloatVectorOperations::min (getDataPointer (ch), src1.getDataPointer (ch), src2.getDataPointer (ch), n);\r
}\r
\r
template <typename Src1SampleType, typename Src2SampleType>\r
auto n = static_cast<int> (jmin (src1.numSamples, src2.numSamples, numSamples) * sizeFactor);\r
\r
for (size_t ch = 0; ch < numChannels; ++ch)\r
- FloatVectorOperations::max (getChannelPointer (ch), src1.getChannelPointer (ch), src2.getChannelPointer (ch), n);\r
+ FloatVectorOperations::max (getDataPointer (ch), src1.getDataPointer (ch), src2.getDataPointer (ch), n);\r
}\r
\r
//==============================================================================\r
namespace dsp\r
{\r
\r
+template <typename SampleType>\r
class AudioBlockUnitTests : public UnitTest\r
{\r
public:\r
+ //==============================================================================\r
+ using NumericType = typename SampleTypeHelpers::ElementType<SampleType>::Type;\r
+\r
AudioBlockUnitTests()\r
: UnitTest ("AudioBlock", UnitTestCategories::dsp)\r
- {}\r
+ {\r
+ for (auto v : { &data, &otherData })\r
+ for (auto& channel : *v)\r
+ channel = allocateAlignedMemory (numSamples);\r
+\r
+ block = { data.data(), data.size(), (size_t) numSamples };\r
+ otherBlock = { otherData.data(), otherData.size(), (size_t) numSamples };\r
+\r
+ resetBlocks();\r
+ }\r
+\r
+ ~AudioBlockUnitTests() override\r
+ {\r
+ for (auto v : { &data, &otherData })\r
+ for (auto channel : *v)\r
+ deallocateAlignedMemory (channel);\r
+ }\r
\r
void runTest() override\r
{\r
\r
beginTest ("Constructors");\r
{\r
- expect (block == AudioBlock<float> (data.getArrayOfWritePointers(), (size_t) data.getNumChannels(), (size_t) data.getNumSamples()));\r
- expect (block == AudioBlock<float> (data.getArrayOfWritePointers(), (size_t) data.getNumChannels(), (size_t) 0, (size_t) data.getNumSamples()));\r
- expect (block == AudioBlock<float> (block));\r
+ expect (block == AudioBlock<SampleType> (data.data(), data.size(), numSamples));\r
+ expect (block == AudioBlock<SampleType> (data.data(), data.size(), (size_t) 0, numSamples));\r
+ expect (block == AudioBlock<SampleType> (block));\r
\r
- expect (block == AudioBlock<const float> (data.getArrayOfWritePointers(), (size_t) data.getNumChannels(), (size_t) data.getNumSamples()));\r
- expect (block == AudioBlock<const float> (data.getArrayOfWritePointers(), (size_t) data.getNumChannels(), (size_t) 0, (size_t) data.getNumSamples()));\r
- expect (block == AudioBlock<const float> (block));\r
+ expect (block == AudioBlock<const SampleType> (data.data(), data.size(), numSamples));\r
+ expect (block == AudioBlock<const SampleType> (data.data(), data.size(), (size_t) 0, numSamples));\r
+ expect (block == AudioBlock<const SampleType> (block));\r
}\r
\r
beginTest ("Swap");\r
resetBlocks();\r
\r
expect (block != otherBlock);\r
- expectEquals (block.getSample (0, 0), 1.0f);\r
- expectEquals (block.getSample (0, 4), 5.0f);\r
- expectEquals (otherBlock.getSample (0, 0), -1.0f);\r
- expectEquals (otherBlock.getSample (0, 3), -4.0f);\r
+ expect (block.getSample (0, 0) == SampleType (1.0));\r
+ expect (block.getSample (0, 4) == SampleType (5.0));\r
+ expect (otherBlock.getSample (0, 0) == SampleType (-1.0));\r
+ expect (otherBlock.getSample (0, 3) == SampleType (-4.0));\r
\r
block.swap (otherBlock);\r
\r
expect (block != otherBlock);\r
- expectEquals (otherBlock.getSample (0, 0), 1.0f);\r
- expectEquals (otherBlock.getSample (0, 4), 5.0f);\r
- expectEquals (block.getSample (0, 0), -1.0f);\r
- expectEquals (block.getSample (0, 3), -4.0f);\r
+ expect (otherBlock.getSample (0, 0) == SampleType (1.0));\r
+ expect (otherBlock.getSample (0, 4) == SampleType (5.0));\r
+ expect (block.getSample (0, 0) == SampleType (-1.0));\r
+ expect (block.getSample (0, 3) == SampleType (-4.0));\r
+\r
+ block.swap (otherBlock);\r
+\r
+ expect (block.getSample (0, 0) == SampleType (1.0));\r
+ expect (block.getSample (0, 4) == SampleType (5.0));\r
+ expect (otherBlock.getSample (0, 0) == SampleType (-1.0));\r
+ expect (otherBlock.getSample (0, 3) == SampleType (-4.0));\r
}\r
\r
beginTest ("Getters and setters");\r
{\r
resetBlocks();\r
\r
- expectEquals ((int) block.getNumChannels(), data.getNumChannels());\r
- expectEquals ((int) block.getNumSamples(), data.getNumSamples());\r
+ expectEquals ((int) block.getNumChannels(), (int) data.size());\r
+ expectEquals ((int) block.getNumSamples(), numSamples);\r
\r
- expectEquals (block.getChannelPointer (0)[2], 3.0f);\r
- block.getChannelPointer (0)[2] = 999.0f;\r
- expectEquals (block.getChannelPointer (0)[2], 999.0f);\r
+ expect (block.getChannelPointer (0)[2] == SampleType (3.0));\r
+ block.getChannelPointer (0)[2] = SampleType (999.0);\r
+ expect (block.getChannelPointer (0)[2] == SampleType (999.0));\r
\r
- expectEquals (block.getSample (0, 4), 5.0f);\r
- expectEquals (block.getSample (1, 4), 11.0f);\r
+ expect (block.getSample (0, 4) == SampleType (5.0));\r
+ expect (block.getSample (1, 4) == SampleType (11.0));\r
\r
- expectEquals (block.getSingleChannelBlock (1).getSample (0, 3), block.getSample (1, 3));\r
+ expect (block.getSingleChannelBlock (1).getSample (0, 3) == block.getSample (1, 3));\r
\r
- expectEquals (block.getSubsetChannelBlock (0, 2).getSample (1, 3), block.getSample (1, 3));\r
- expectEquals (block.getSubsetChannelBlock (1, 1).getSample (0, 3), block.getSample (1, 3));\r
+ expect (block.getSubsetChannelBlock (0, 2).getSample (1, 3) == block.getSample (1, 3));\r
+ expect (block.getSubsetChannelBlock (1, 1).getSample (0, 3) == block.getSample (1, 3));\r
\r
- block.setSample (1, 1, 777.0f);\r
- expectEquals (block.getSample (1, 1), 777.0f);\r
+ block.setSample (1, 1, SampleType (777.0));\r
+ expect (block.getSample (1, 1) == SampleType (777.0));\r
\r
- block.addSample (1, 1, 1.0f);\r
- expectEquals (block.getSample (1, 1), 778.0f);\r
+ block.addSample (1, 1, SampleType (1.0));\r
+ expect (block.getSample (1, 1) == SampleType (778.0));\r
}\r
\r
- beginTest ("Copying");\r
+ beginTest ("Basic copying");\r
{\r
block.clear();\r
- expectEquals (block.getSample (0, 2), 0.0f);\r
- expectEquals (block.getSample (1, 4), 0.0f);\r
+ expect (block.getSample (0, 2) == SampleType (0.0));\r
+ expect (block.getSample (1, 4) == SampleType (0.0));\r
\r
- block.fill (456.0f);\r
- expectEquals (block.getSample (0, 2), 456.0f);\r
- expectEquals (block.getSample (1, 4), 456.0f);\r
+ block.fill ((NumericType) 456.0);\r
+ expect (block.getSample (0, 2) == SampleType (456.0));\r
+ expect (block.getSample (1, 4) == SampleType (456.0));\r
\r
block.copyFrom (otherBlock);\r
expect (block != otherBlock);\r
- expectEquals (block.getSample (0, 2), otherBlock.getSample (0, 2));\r
- expectEquals (block.getSample (1, 4), otherBlock.getSample (1, 4));\r
+ expect (block.getSample (0, 2) == otherBlock.getSample (0, 2));\r
+ expect (block.getSample (1, 4) == otherBlock.getSample (1, 4));\r
\r
resetBlocks();\r
\r
- AudioBuffer<float> otherBuffer ((int) block.getNumChannels(), (int) block.getNumSamples());\r
- otherBlock.copyTo (otherBuffer);\r
- expectEquals (otherBlock.getSample (0, 2), otherBuffer.getSample (0, 2));\r
- expectEquals (otherBlock.getSample (1, 4), otherBuffer.getSample (1, 4));\r
-\r
- block.copyFrom (otherBuffer);\r
- expectEquals (block.getSample (0, 2), otherBlock.getSample (0, 2));\r
- expectEquals (block.getSample (1, 4), otherBlock.getSample (1, 4));\r
-\r
- float testSample1 = block.getSample (0, 2);\r
- float testSample2 = block.getSample (1, 3);\r
+ SampleType testSample1 = block.getSample (0, 2);\r
+ SampleType testSample2 = block.getSample (1, 3);\r
expect (testSample1 != block.getSample (0, 4));\r
expect (testSample2 != block.getSample (1, 5));\r
block.move (0, 2);\r
- expectEquals (block.getSample (0, 4), testSample1);\r
- expectEquals (block.getSample (1, 5), testSample2);\r
+ expect (block.getSample (0, 4) == testSample1);\r
+ expect (block.getSample (1, 5) == testSample2);\r
}\r
\r
beginTest ("Addition");\r
{\r
resetBlocks();\r
\r
- block.add (15.0f);\r
- expectEquals (block.getSample (0, 4), 20.0f);\r
- expectEquals (block.getSample (1, 4), 26.0f);\r
+ block.add ((NumericType) 15.0);\r
+ expect (block.getSample (0, 4) == SampleType (20.0));\r
+ expect (block.getSample (1, 4) == SampleType (26.0));\r
\r
block.add (otherBlock);\r
- expectEquals (block.getSample (0, 4), 15.0f);\r
- expectEquals (block.getSample (1, 4), 15.0f);\r
+ expect (block.getSample (0, 4) == SampleType (15.0));\r
+ expect (block.getSample (1, 4) == SampleType (15.0));\r
\r
- block.replaceWithSumOf (otherBlock, 9.0f);\r
- expectEquals (block.getSample (0, 4), 4.0f);\r
- expectEquals (block.getSample (1, 4), -2.0f);\r
+ block.replaceWithSumOf (otherBlock, (NumericType) 9.0);\r
+ expect (block.getSample (0, 4) == SampleType (4.0));\r
+ expect (block.getSample (1, 4) == SampleType (-2.0));\r
\r
resetBlocks();\r
\r
block.replaceWithSumOf (block, otherBlock);\r
- expectEquals (block.getSample (0, 4), 0.0f);\r
- expectEquals (block.getSample (1, 4), 0.0f);\r
+ expect (block.getSample (0, 4) == SampleType (0.0));\r
+ expect (block.getSample (1, 4) == SampleType (0.0));\r
}\r
\r
beginTest ("Subtraction");\r
{\r
resetBlocks();\r
\r
- block.subtract (15.0f);\r
- expectEquals (block.getSample (0, 4), -10.0f);\r
- expectEquals (block.getSample (1, 4), -4.0f);\r
+ block.subtract ((NumericType) 15.0);\r
+ expect (block.getSample (0, 4) == SampleType (-10.0));\r
+ expect (block.getSample (1, 4) == SampleType (-4.0));\r
\r
block.subtract (otherBlock);\r
- expectEquals (block.getSample (0, 4), -5.0f);\r
- expectEquals (block.getSample (1, 4), 7.0f);\r
+ expect (block.getSample (0, 4) == SampleType (-5.0));\r
+ expect (block.getSample (1, 4) == SampleType (7.0));\r
\r
- block.replaceWithDifferenceOf (otherBlock, 9.0f);\r
- expectEquals (block.getSample (0, 4), -14.0f);\r
- expectEquals (block.getSample (1, 4), -20.0f);\r
+ block.replaceWithDifferenceOf (otherBlock, (NumericType) 9.0);\r
+ expect (block.getSample (0, 4) == SampleType (-14.0));\r
+ expect (block.getSample (1, 4) == SampleType (-20.0));\r
\r
resetBlocks();\r
\r
block.replaceWithDifferenceOf (block, otherBlock);\r
- expectEquals (block.getSample (0, 4), 10.0f);\r
- expectEquals (block.getSample (1, 4), 22.0f);\r
+ expect (block.getSample (0, 4) == SampleType (10.0));\r
+ expect (block.getSample (1, 4) == SampleType (22.0));\r
}\r
\r
beginTest ("Multiplication");\r
{\r
resetBlocks();\r
\r
- block.multiplyBy (10.0f);\r
- expectEquals (block.getSample (0, 4), 50.0f);\r
- expectEquals (block.getSample (1, 4), 110.0f);\r
+ block.multiplyBy ((NumericType) 10.0);\r
+ expect (block.getSample (0, 4) == SampleType (50.0));\r
+ expect (block.getSample (1, 4) == SampleType (110.0));\r
\r
block.multiplyBy (otherBlock);\r
- expectEquals (block.getSample (0, 4), -250.0f);\r
- expectEquals (block.getSample (1, 4), -1210.0f);\r
+ expect (block.getSample (0, 4) == SampleType (-250.0));\r
+ expect (block.getSample (1, 4) == SampleType (-1210.0));\r
\r
- block.replaceWithProductOf (otherBlock, 3.0f);\r
- expectEquals (block.getSample (0, 4), -15.0f);\r
- expectEquals (block.getSample (1, 4), -33.0f);\r
+ block.replaceWithProductOf (otherBlock, (NumericType) 3.0);\r
+ expect (block.getSample (0, 4) == SampleType (-15.0));\r
+ expect (block.getSample (1, 4) == SampleType (-33.0));\r
\r
resetBlocks();\r
\r
block.replaceWithProductOf (block, otherBlock);\r
- expectEquals (block.getSample (0, 4), -25.0f);\r
- expectEquals (block.getSample (1, 4), -121.0f);\r
- }\r
-\r
- beginTest ("Smoothing");\r
- {\r
- block.fill (1.0f);\r
- SmoothedValue<float> sv { 1.0f };\r
- sv.reset (1, 4);\r
- sv.setTargetValue (0.0f);\r
-\r
- block.multiplyBy (sv);\r
- expect (block.getSample (0, 2) < 1.0f);\r
- expect (block.getSample (1, 2) < 1.0f);\r
- expect (block.getSample (0, 2) > 0.0f);\r
- expect (block.getSample (1, 2) > 0.0f);\r
- expectEquals (block.getSample (0, 5), 0.0f);\r
- expectEquals (block.getSample (1, 5), 0.0f);\r
-\r
- sv.setCurrentAndTargetValue (-1.0f);\r
- sv.setTargetValue (0.0f);\r
- otherBlock.fill (-1.0f);\r
- block.replaceWithProductOf (otherBlock, sv);\r
- expect (block.getSample (0, 2) < 1.0f);\r
- expect (block.getSample (1, 2) < 1.0f);\r
- expect (block.getSample (0, 2) > 0.0f);\r
- expect (block.getSample (1, 2) > 0.0f);\r
- expectEquals (block.getSample (0, 5), 0.0f);\r
- expectEquals (block.getSample (1, 5), 0.0f);\r
+ expect (block.getSample (0, 4) == SampleType (-25.0));\r
+ expect (block.getSample (1, 4) == SampleType (-121.0));\r
}\r
\r
beginTest ("Multiply add");\r
{\r
resetBlocks();\r
\r
- block.addProductOf (otherBlock, -1.0f);\r
- expectEquals (block.getSample (0, 4), 10.0f);\r
- expectEquals (block.getSample (1, 4), 22.0f);\r
+ block.addProductOf (otherBlock, (NumericType) -1.0);\r
+ expect (block.getSample (0, 4) == SampleType (10.0));\r
+ expect (block.getSample (1, 4) == SampleType (22.0));\r
\r
block.addProductOf (otherBlock, otherBlock);\r
- expectEquals (block.getSample (0, 4), 35.0f);\r
- expectEquals (block.getSample (1, 4), 143.0f);\r
+ expect (block.getSample (0, 4) == SampleType (35.0));\r
+ expect (block.getSample (1, 4) == SampleType (143.0));\r
}\r
\r
beginTest ("Negative abs min max");\r
otherBlock.negate();\r
\r
block.add (otherBlock);\r
- expectEquals (block.getSample (0, 4), 10.0f);\r
- expectEquals (block.getSample (1, 4), 22.0f);\r
+ expect (block.getSample (0, 4) == SampleType (10.0));\r
+ expect (block.getSample (1, 4) == SampleType (22.0));\r
\r
block.replaceWithNegativeOf (otherBlock);\r
- expectEquals (block.getSample (0, 4), -5.0f);\r
- expectEquals (block.getSample (1, 4), -11.0f);\r
+ expect (block.getSample (0, 4) == SampleType (-5.0));\r
+ expect (block.getSample (1, 4) == SampleType (-11.0));\r
\r
block.clear();\r
otherBlock.negate();\r
block.replaceWithAbsoluteValueOf (otherBlock);\r
- expectEquals (block.getSample (0, 4), 5.0f);\r
- expectEquals (block.getSample (1, 4), 11.0f);\r
+ expect (block.getSample (0, 4) == SampleType (5.0));\r
+ expect (block.getSample (1, 4) == SampleType (11.0));\r
\r
resetBlocks();\r
block.replaceWithMinOf (block, otherBlock);\r
- expectEquals (block.getSample (0, 4), -5.0f);\r
- expectEquals (block.getSample (1, 4), -11.0f);\r
+ expect (block.getSample (0, 4) == SampleType (-5.0));\r
+ expect (block.getSample (1, 4) == SampleType (-11.0));\r
\r
resetBlocks();\r
block.replaceWithMaxOf (block, otherBlock);\r
- expectEquals (block.getSample (0, 4), 5.0f);\r
- expectEquals (block.getSample (1, 4), 11.0f);\r
+ expect (block.getSample (0, 4) == SampleType (5.0));\r
+ expect (block.getSample (1, 4) == SampleType (11.0));\r
\r
resetBlocks();\r
auto range = block.findMinAndMax();\r
- expectEquals (range.getStart(), 1.0f);\r
- expectEquals (range.getEnd(), 12.0f);\r
+ expect (SampleType (range.getStart()) == SampleType (1.0));\r
+ expect (SampleType (range.getEnd()) == SampleType (12.0));\r
}\r
\r
beginTest ("Operators");\r
{\r
resetBlocks();\r
- block += 10.0f;\r
- expectEquals (block.getSample (0, 4), 15.0f);\r
- expectEquals (block.getSample (1, 4), 21.0f);\r
+ block += (NumericType) 10.0;\r
+ expect (block.getSample (0, 4) == SampleType (15.0));\r
+ expect (block.getSample (1, 4) == SampleType (21.0));\r
block += otherBlock;\r
- expectEquals (block.getSample (0, 4), 10.0f);\r
- expectEquals (block.getSample (1, 4), 10.0f);\r
+ expect (block.getSample (0, 4) == SampleType (10.0));\r
+ expect (block.getSample (1, 4) == SampleType (10.0));\r
\r
resetBlocks();\r
- block -= 10.0f;\r
- expectEquals (block.getSample (0, 4), -5.0f);\r
- expectEquals (block.getSample (1, 4), 1.0f);\r
+ block -= (NumericType) 10.0;\r
+ expect (block.getSample (0, 4) == SampleType (-5.0));\r
+ expect (block.getSample (1, 4) == SampleType (1.0));\r
block -= otherBlock;\r
- expectEquals (block.getSample (0, 4), 0.0f);\r
- expectEquals (block.getSample (1, 4), 12.0f);\r
+ expect (block.getSample (0, 4) == SampleType (0.0));\r
+ expect (block.getSample (1, 4) == SampleType (12.0));\r
\r
resetBlocks();\r
- block *= 10.0f;\r
- expectEquals (block.getSample (0, 4), 50.0f);\r
- expectEquals (block.getSample (1, 4), 110.0f);\r
+ block *= (NumericType) 10.0;\r
+ expect (block.getSample (0, 4) == SampleType (50.0));\r
+ expect (block.getSample (1, 4) == SampleType (110.0));\r
block *= otherBlock;\r
- expectEquals (block.getSample (0, 4), -250.0f);\r
- expectEquals (block.getSample (1, 4), -1210.0f);\r
+ expect (block.getSample (0, 4) == SampleType (-250.0));\r
+ expect (block.getSample (1, 4) == SampleType (-1210.0));\r
}\r
\r
beginTest ("Process");\r
{\r
resetBlocks();\r
- AudioBlock<float>::process (block, otherBlock, [](float x) { return x + 1.0f; });\r
- expectEquals (otherBlock.getSample (0, 4), 6.0f);\r
- expectEquals (otherBlock.getSample (1, 4), 12.0f);\r
+ AudioBlock<SampleType>::process (block, otherBlock, [](SampleType x) { return x + (NumericType) 1.0; });\r
+ expect (otherBlock.getSample (0, 4) == SampleType (6.0));\r
+ expect (otherBlock.getSample (1, 4) == SampleType (12.0));\r
+ }\r
+\r
+ beginTest ("Copying");\r
+ {\r
+ resetBlocks();\r
+ copyingTests();\r
+ }\r
+\r
+ beginTest ("Smoothing");\r
+ {\r
+ resetBlocks();\r
+ smoothedValueTests();\r
}\r
}\r
\r
private:\r
- AudioBuffer<float> data { 2, 6 }, otherData { 2, 6 };\r
- AudioBlock<float> block { data }, otherBlock { otherData };\r
+ //==============================================================================\r
+ template <typename T>\r
+ using ScalarVoid = typename std::enable_if_t < std::is_scalar <T>::value, void>;\r
+\r
+ template <typename T>\r
+ using SIMDVoid = typename std::enable_if_t <! std::is_scalar <T>::value, void>;\r
+\r
+ //==============================================================================\r
+ template <typename T = SampleType>\r
+ ScalarVoid<T> copyingTests()\r
+ {\r
+ auto unchangedElement1 = block.getSample (0, 4);\r
+ auto unchangedElement2 = block.getSample (1, 1);\r
+\r
+ AudioBuffer<SampleType> otherBuffer (otherData.data(), (int) otherData.size(), numSamples);\r
+\r
+ block.copyFrom (otherBuffer, 1, 2, 2);\r
+\r
+ expectEquals (block.getSample (0, 4), unchangedElement1);\r
+ expectEquals (block.getSample (1, 1), unchangedElement2);\r
+ expectEquals (block.getSample (0, 2), otherBuffer.getSample (0, 1));\r
+ expectEquals (block.getSample (1, 3), otherBuffer.getSample (1, 2));\r
\r
+ resetBlocks();\r
+\r
+ unchangedElement1 = otherBuffer.getSample (0, 4);\r
+ unchangedElement2 = otherBuffer.getSample (1, 3);\r
+\r
+ block.copyTo (otherBuffer, 2, 1, 2);\r
+\r
+ expectEquals (otherBuffer.getSample (0, 4), unchangedElement1);\r
+ expectEquals (otherBuffer.getSample (1, 3), unchangedElement2);\r
+ expectEquals (otherBuffer.getSample (0, 1), block.getSample (0, 2));\r
+ expectEquals (otherBuffer.getSample (1, 2), block.getSample (1, 3));\r
+ }\r
+\r
+ template <typename T = SampleType>\r
+ SIMDVoid<T> copyingTests()\r
+ {\r
+ auto numSIMDElements = SIMDRegister<NumericType>::SIMDNumElements;\r
+ AudioBuffer<NumericType> numericData ((int) block.getNumChannels(),\r
+ (int) (block.getNumSamples() * numSIMDElements));\r
+\r
+ for (int c = 0; c < numericData.getNumChannels(); ++c)\r
+ std::fill_n (numericData.getWritePointer (c), numericData.getNumSamples(), (NumericType) 1.0);\r
+\r
+ numericData.applyGainRamp (0, numericData.getNumSamples(), (NumericType) 0.127, (NumericType) 17.3);\r
+\r
+ auto lastUnchangedIndexBeforeCopiedRange = (int) ((numSIMDElements * 2) - 1);\r
+ auto firstUnchangedIndexAfterCopiedRange = (int) ((numSIMDElements * 4) + 1);\r
+ auto unchangedElement1 = numericData.getSample (0, lastUnchangedIndexBeforeCopiedRange);\r
+ auto unchangedElement2 = numericData.getSample (1, firstUnchangedIndexAfterCopiedRange);\r
+\r
+ block.copyTo (numericData, 1, 2, 2);\r
+\r
+ expectEquals (numericData.getSample (0, lastUnchangedIndexBeforeCopiedRange), unchangedElement1);\r
+ expectEquals (numericData.getSample (1, firstUnchangedIndexAfterCopiedRange), unchangedElement2);\r
+ expect (SampleType (numericData.getSample (0, 2 * (int) numSIMDElements)) == block.getSample (0, 1));\r
+ expect (SampleType (numericData.getSample (1, 3 * (int) numSIMDElements)) == block.getSample (1, 2));\r
+\r
+ numericData.applyGainRamp (0, numericData.getNumSamples(), (NumericType) 15.1, (NumericType) 0.7);\r
+\r
+ auto unchangedSIMDElement1 = block.getSample (0, 1);\r
+ auto unchangedSIMDElement2 = block.getSample (1, 4);\r
+\r
+ block.copyFrom (numericData, 1, 2, 2);\r
+\r
+ expect (block.getSample (0, 1) == unchangedSIMDElement1);\r
+ expect (block.getSample (1, 4) == unchangedSIMDElement2);\r
+ expectEquals (block.getSample (0, 2).get (0), numericData.getSample (0, (int) numSIMDElements));\r
+ expectEquals (block.getSample (1, 3).get (0), numericData.getSample (1, (int) (numSIMDElements * 2)));\r
+\r
+ if (numSIMDElements > 1)\r
+ {\r
+ expectEquals (block.getSample (0, 2).get (1), numericData.getSample (0, (int) (numSIMDElements + 1)));\r
+ expectEquals (block.getSample (1, 3).get (1), numericData.getSample (1, (int) ((numSIMDElements * 2) + 1)));\r
+ }\r
+ }\r
+\r
+ //==============================================================================\r
+ template <typename T = SampleType>\r
+ ScalarVoid<T> smoothedValueTests()\r
+ {\r
+ block.fill ((SampleType) 1.0);\r
+ SmoothedValue<SampleType> sv { (SampleType) 1.0 };\r
+ sv.reset (1, 4);\r
+ sv.setTargetValue ((SampleType) 0.0);\r
+\r
+ block.multiplyBy (sv);\r
+ expect (block.getSample (0, 2) < (SampleType) 1.0);\r
+ expect (block.getSample (1, 2) < (SampleType) 1.0);\r
+ expect (block.getSample (0, 2) > (SampleType) 0.0);\r
+ expect (block.getSample (1, 2) > (SampleType) 0.0);\r
+ expectEquals (block.getSample (0, 5), (SampleType) 0.0);\r
+ expectEquals (block.getSample (1, 5), (SampleType) 0.0);\r
+\r
+ sv.setCurrentAndTargetValue (-1.0f);\r
+ sv.setTargetValue (0.0f);\r
+ otherBlock.fill (-1.0f);\r
+ block.replaceWithProductOf (otherBlock, sv);\r
+ expect (block.getSample (0, 2) < (SampleType) 1.0);\r
+ expect (block.getSample (1, 2) < (SampleType) 1.0);\r
+ expect (block.getSample (0, 2) > (SampleType) 0.0);\r
+ expect (block.getSample (1, 2) > (SampleType) 0.0);\r
+ expectEquals (block.getSample (0, 5), (SampleType) 0.0);\r
+ expectEquals (block.getSample (1, 5), (SampleType) 0.0);\r
+ }\r
+\r
+ template <typename T = SampleType>\r
+ SIMDVoid<T> smoothedValueTests() {}\r
+\r
+ //==============================================================================\r
void resetBlocks()\r
{\r
- auto value = 1.0f;\r
+ auto value = SampleType (1.0);\r
\r
for (size_t c = 0; c < block.getNumChannels(); ++c)\r
{\r
for (size_t i = 0; i < block.getNumSamples(); ++i)\r
{\r
block.setSample ((int) c, (int) i, value);\r
- value += 1.0f;\r
+ value += SampleType (1.0);\r
}\r
}\r
\r
otherBlock.replaceWithNegativeOf (block);\r
}\r
+\r
+ //==============================================================================\r
+ static SampleType* allocateAlignedMemory (int numSamplesToAllocate)\r
+ {\r
+ auto alignmentLowerBound = std::alignment_of<SampleType>::value;\r
+ #if ! JUCE_WINDOWS\r
+ alignmentLowerBound = jmax (sizeof (void*), alignmentLowerBound);\r
+ #endif\r
+ auto alignmentOrder = std::ceil (std::log2 (alignmentLowerBound));\r
+ auto requiredAlignment = (size_t) std::pow (2, alignmentOrder);\r
+\r
+ auto size = (size_t) numSamplesToAllocate * sizeof (SampleType);\r
+\r
+ #if JUCE_WINDOWS\r
+ auto* memory = _aligned_malloc (size, requiredAlignment);\r
+ #else\r
+ void* memory;\r
+ auto result = posix_memalign (&memory, requiredAlignment, size);\r
+\r
+ if (result != 0)\r
+ {\r
+ jassertfalse;\r
+ return nullptr;\r
+ }\r
+ #endif\r
+\r
+ return static_cast<SampleType*> (memory);\r
+ }\r
+\r
+ void deallocateAlignedMemory (void* address)\r
+ {\r
+ #if JUCE_WINDOWS\r
+ _aligned_free (address);\r
+ #else\r
+ free (address);\r
+ #endif\r
+ }\r
+\r
+ //==============================================================================\r
+ static constexpr int numChannels = 2, numSamples = 6;\r
+ std::array<SampleType*, numChannels> data, otherData;\r
+ AudioBlock<SampleType> block, otherBlock;\r
};\r
\r
-static AudioBlockUnitTests audioBlockUnitTests;\r
+static AudioBlockUnitTests<float> audioBlockFloatUnitTests;\r
+static AudioBlockUnitTests<double> audioBlockDoubleUnitTests;\r
+static AudioBlockUnitTests<SIMDRegister<float>> audioBlockSIMDFloatUnitTests;\r
+static AudioBlockUnitTests<SIMDRegister<double>> audioBlockSIMDDoubleUnitTests;\r
\r
} // namespace dsp\r
} // namespace juce\r
A wrapper around the platform's native SIMD register type.\r
\r
This class is only available on SIMD machines. Use JUCE_USE_SIMD to query\r
- if SIMD is avaialble for your system.\r
+ if SIMD is available for your system.\r
\r
SIMDRegister<Type> is a templated class representing the native\r
vectorized version of FloatingType. SIMDRegister supports all numerical\r
/** Constructs an object from a scalar type by broadcasting it to all elements. */\r
inline SIMDRegister (Type s) noexcept { *this = s; }\r
\r
- /** Destrutor. */\r
+ /** Destructor. */\r
inline ~SIMDRegister() noexcept = default;\r
\r
//==============================================================================\r
inline SIMDRegister& JUCE_VECTOR_CALLTYPE operator*= (ElementType s) noexcept { value = CmplxOps::mul (value, CmplxOps::expand (s)); return *this; }\r
\r
//==============================================================================\r
- /** Bit-and the reciver with SIMDRegister v and store the result in the receiver. */\r
+ /** Bit-and the receiver with SIMDRegister v and store the result in the receiver. */\r
inline SIMDRegister& JUCE_VECTOR_CALLTYPE operator&= (vMaskType v) noexcept { value = NativeOps::bit_and (value, toVecType (v.value)); return *this; }\r
\r
- /** Bit-or the reciver with SIMDRegister v and store the result in the receiver. */\r
+ /** Bit-or the receiver with SIMDRegister v and store the result in the receiver. */\r
inline SIMDRegister& JUCE_VECTOR_CALLTYPE operator|= (vMaskType v) noexcept { value = NativeOps::bit_or (value, toVecType (v.value)); return *this; }\r
\r
- /** Bit-xor the reciver with SIMDRegister v and store the result in the receiver. */\r
+ /** Bit-xor the receiver with SIMDRegister v and store the result in the receiver. */\r
inline SIMDRegister& JUCE_VECTOR_CALLTYPE operator^= (vMaskType v) noexcept { value = NativeOps::bit_xor (value, toVecType (v.value)); return *this; }\r
\r
//==============================================================================\r
- /** Bit-and each element of the reciver with the scalar s and store the result in the receiver.*/\r
+ /** Bit-and each element of the receiver with the scalar s and store the result in the receiver.*/\r
inline SIMDRegister& JUCE_VECTOR_CALLTYPE operator&= (MaskType s) noexcept { value = NativeOps::bit_and (value, toVecType (s)); return *this; }\r
\r
- /** Bit-or each element of the reciver with the scalar s and store the result in the receiver.*/\r
+ /** Bit-or each element of the receiver with the scalar s and store the result in the receiver.*/\r
inline SIMDRegister& JUCE_VECTOR_CALLTYPE operator|= (MaskType s) noexcept { value = NativeOps::bit_or (value, toVecType (s)); return *this; }\r
\r
- /** Bit-xor each element of the reciver with the scalar s and store the result in the receiver.*/\r
+ /** Bit-xor each element of the receiver with the scalar s and store the result in the receiver.*/\r
inline SIMDRegister& JUCE_VECTOR_CALLTYPE operator^= (MaskType s) noexcept { value = NativeOps::bit_xor (value, toVecType (s)); return *this; }\r
\r
//==============================================================================\r
inline SIMDRegister JUCE_VECTOR_CALLTYPE operator^ (MaskType s) const noexcept { return { NativeOps::bit_xor (value, toVecType (s)) }; }\r
\r
//==============================================================================\r
- /** Returns true if all elements-wise comparisons return true. */\r
+ /** Returns true if all element-wise comparisons return true. */\r
inline bool JUCE_VECTOR_CALLTYPE operator== (SIMDRegister other) const noexcept { return NativeOps::allEqual (value, other.value); }\r
\r
- /** Returns true if any elements-wise comparisons return false. */\r
+ /** Returns true if any element-wise comparisons return false. */\r
inline bool JUCE_VECTOR_CALLTYPE operator!= (SIMDRegister other) const noexcept { return ! (*this == other); }\r
\r
/** Returns true if all elements are equal to the scalar. */\r
}\r
\r
//==============================================================================\r
- // Someuseful operations to test\r
+ // Some useful operations to test\r
struct Addition\r
{\r
template <typename typeOne, typename typeTwo>\r
\r
/** Performs an in-place forward transform on a block of real data.\r
\r
- As the coefficients of the negative frequences (frequencies higher than\r
+ As the coefficients of the negative frequencies (frequencies higher than\r
N/2 or pi) are the complex conjugate of their positive counterparts,\r
it may not be necessary to calculate them for your particular application.\r
You can use dontCalculateNegativeFrequencies to let the FFT\r
\r
ID: juce_dsp\r
vendor: juce\r
- version: 5.4.5\r
+ version: 5.4.6\r
name: JUCE DSP classes\r
description: Classes for audio buffer manipulation, digital audio processing, filtering, oversampling, fast math functions etc.\r
website: http://www.juce.com/juce\r
with the coefficients of b. After the execution of the algorithm,\r
the vector b will contain the solution.\r
\r
- Returns true if the linear system of euqations was successfully solved.\r
+ Returns true if the linear system of equations was successfully solved.\r
*/\r
bool solve (Matrix& b) const noexcept;\r
\r
@param newValue a value between 0 and 1; higher values increase the resonance and can result in self oscillation! */\r
void setResonance (Type newValue) noexcept;\r
\r
- /** Sets the amound of saturation in the filter.\r
+ /** Sets the amount of saturation in the filter.\r
@param newValue saturation amount; it can be any number greater than or equal to one. Higher values result in more distortion.*/\r
void setDrive (Type newValue) noexcept;\r
\r
auto&& outBlock = context.getOutputBlock();\r
auto&& inBlock = context.getInputBlock();\r
\r
- // this is an output-only processory\r
+ // this is an output-only processor\r
jassert (outBlock.getNumSamples() <= static_cast<size_t> (rampBuffer.size()));\r
\r
auto len = outBlock.getNumSamples();\r
buffer.clear();\r
}\r
\r
- dsp::AudioBlock<SampleType> getProcessedSamples (size_t numSamples)\r
+ AudioBlock<SampleType> getProcessedSamples (size_t numSamples)\r
{\r
- return dsp::AudioBlock<SampleType> (buffer).getSubBlock (0, numSamples);\r
+ return AudioBlock<SampleType> (buffer).getSubBlock (0, numSamples);\r
}\r
\r
- virtual void processSamplesUp (dsp::AudioBlock<SampleType>&) = 0;\r
- virtual void processSamplesDown (dsp::AudioBlock<SampleType>&) = 0;\r
+ virtual void processSamplesUp (const AudioBlock<const SampleType>&) = 0;\r
+ virtual void processSamplesDown (AudioBlock<SampleType>&) = 0;\r
\r
AudioBuffer<SampleType> buffer;\r
size_t numChannels, factor;\r
return 0;\r
}\r
\r
- void processSamplesUp (dsp::AudioBlock<SampleType>& inputBlock) override\r
+ void processSamplesUp (const AudioBlock<const SampleType>& inputBlock) override\r
{\r
jassert (inputBlock.getNumChannels() <= static_cast<size_t> (ParentType::buffer.getNumChannels()));\r
jassert (inputBlock.getNumSamples() * ParentType::factor <= static_cast<size_t> (ParentType::buffer.getNumSamples()));\r
inputBlock.getChannelPointer (channel), static_cast<int> (inputBlock.getNumSamples()));\r
}\r
\r
- void processSamplesDown (dsp::AudioBlock<SampleType>& outputBlock) override\r
+ void processSamplesDown (AudioBlock<SampleType>& outputBlock) override\r
{\r
jassert (outputBlock.getNumChannels() <= static_cast<size_t> (ParentType::buffer.getNumChannels()));\r
jassert (outputBlock.getNumSamples() * ParentType::factor <= static_cast<size_t> (ParentType::buffer.getNumSamples()));\r
SampleType stopbandAmplitudedBDown)\r
: ParentType (numChans, 2)\r
{\r
- coefficientsUp = *dsp::FilterDesign<SampleType>::designFIRLowpassHalfBandEquirippleMethod (normalisedTransitionWidthUp, stopbandAmplitudedBUp);\r
- coefficientsDown = *dsp::FilterDesign<SampleType>::designFIRLowpassHalfBandEquirippleMethod (normalisedTransitionWidthDown, stopbandAmplitudedBDown);\r
+ coefficientsUp = *FilterDesign<SampleType>::designFIRLowpassHalfBandEquirippleMethod (normalisedTransitionWidthUp, stopbandAmplitudedBUp);\r
+ coefficientsDown = *FilterDesign<SampleType>::designFIRLowpassHalfBandEquirippleMethod (normalisedTransitionWidthDown, stopbandAmplitudedBDown);\r
\r
auto N = coefficientsUp.getFilterOrder() + 1;\r
stateUp.setSize (static_cast<int> (this->numChannels), static_cast<int> (N));\r
position.fill (0);\r
}\r
\r
- void processSamplesUp (dsp::AudioBlock<SampleType>& inputBlock) override\r
+ void processSamplesUp (const AudioBlock<const SampleType>& inputBlock) override\r
{\r
jassert (inputBlock.getNumChannels() <= static_cast<size_t> (ParentType::buffer.getNumChannels()));\r
jassert (inputBlock.getNumSamples() * ParentType::factor <= static_cast<size_t> (ParentType::buffer.getNumSamples()));\r
}\r
}\r
\r
- void processSamplesDown (dsp::AudioBlock<SampleType>& outputBlock) override\r
+ void processSamplesDown (AudioBlock<SampleType>& outputBlock) override\r
{\r
jassert (outputBlock.getNumChannels() <= static_cast<size_t> (ParentType::buffer.getNumChannels()));\r
jassert (outputBlock.getNumSamples() * ParentType::factor <= static_cast<size_t> (ParentType::buffer.getNumSamples()));\r
\r
private:\r
//==============================================================================\r
- dsp::FIR::Coefficients<SampleType> coefficientsUp, coefficientsDown;\r
+ FIR::Coefficients<SampleType> coefficientsUp, coefficientsDown;\r
AudioBuffer<SampleType> stateUp, stateDown, stateDown2;\r
Array<size_t> position;\r
\r
SampleType stopbandAmplitudedBDown)\r
: ParentType (numChans, 2)\r
{\r
- auto structureUp = dsp::FilterDesign<SampleType>::designIIRLowpassHalfBandPolyphaseAllpassMethod (normalisedTransitionWidthUp, stopbandAmplitudedBUp);\r
+ auto structureUp = FilterDesign<SampleType>::designIIRLowpassHalfBandPolyphaseAllpassMethod (normalisedTransitionWidthUp, stopbandAmplitudedBUp);\r
auto coeffsUp = getCoefficients (structureUp);\r
latency = static_cast<SampleType> (-(coeffsUp.getPhaseForFrequency (0.0001, 1.0)) / (0.0001 * MathConstants<double>::twoPi));\r
\r
- auto structureDown = dsp::FilterDesign<SampleType>::designIIRLowpassHalfBandPolyphaseAllpassMethod (normalisedTransitionWidthDown, stopbandAmplitudedBDown);\r
+ auto structureDown = FilterDesign<SampleType>::designIIRLowpassHalfBandPolyphaseAllpassMethod (normalisedTransitionWidthDown, stopbandAmplitudedBDown);\r
auto coeffsDown = getCoefficients (structureDown);\r
latency += static_cast<SampleType> (-(coeffsDown.getPhaseForFrequency (0.0001, 1.0)) / (0.0001 * MathConstants<double>::twoPi));\r
\r
delayDown.fill (0);\r
}\r
\r
- void processSamplesUp (dsp::AudioBlock<SampleType>& inputBlock) override\r
+ void processSamplesUp (const AudioBlock<const SampleType>& inputBlock) override\r
{\r
jassert (inputBlock.getNumChannels() <= static_cast<size_t> (ParentType::buffer.getNumChannels()));\r
jassert (inputBlock.getNumSamples() * ParentType::factor <= static_cast<size_t> (ParentType::buffer.getNumSamples()));\r
snapToZero (true);\r
}\r
\r
- void processSamplesDown (dsp::AudioBlock<SampleType>& outputBlock) override\r
+ void processSamplesDown (AudioBlock<SampleType>& outputBlock) override\r
{\r
jassert (outputBlock.getNumChannels() <= static_cast<size_t> (ParentType::buffer.getNumChannels()));\r
jassert (outputBlock.getNumSamples() * ParentType::factor <= static_cast<size_t> (ParentType::buffer.getNumSamples()));\r
/** This function calculates the equivalent high order IIR filter of a given\r
polyphase cascaded allpass filters structure.\r
*/\r
- dsp::IIR::Coefficients<SampleType> getCoefficients (typename dsp::FilterDesign<SampleType>::IIRPolyphaseAllpassStructure& structure) const\r
+ IIR::Coefficients<SampleType> getCoefficients (typename FilterDesign<SampleType>::IIRPolyphaseAllpassStructure& structure) const\r
{\r
constexpr auto one = static_cast<SampleType> (1.0);\r
\r
- dsp::Polynomial<SampleType> numerator1 ({ one }), denominator1 ({ one }),\r
- numerator2 ({ one }), denominator2 ({ one });\r
+ Polynomial<SampleType> numerator1 ({ one }), denominator1 ({ one }),\r
+ numerator2 ({ one }), denominator2 ({ one });\r
\r
for (auto* i : structure.directPath)\r
{\r
\r
if (i->getFilterOrder() == 1)\r
{\r
- numerator1 = numerator1.getProductWith (dsp::Polynomial<SampleType> ({ coeffs[0], coeffs[1] }));\r
- denominator1 = denominator1.getProductWith (dsp::Polynomial<SampleType> ({ one, coeffs[2] }));\r
+ numerator1 = numerator1 .getProductWith (Polynomial<SampleType> ({ coeffs[0], coeffs[1] }));\r
+ denominator1 = denominator1.getProductWith (Polynomial<SampleType> ({ one, coeffs[2] }));\r
}\r
else\r
{\r
- numerator1 = numerator1.getProductWith (dsp::Polynomial<SampleType> ({ coeffs[0], coeffs[1], coeffs[2] }));\r
- denominator1 = denominator1.getProductWith (dsp::Polynomial<SampleType> ({ one, coeffs[3], coeffs[4] }));\r
+ numerator1 = numerator1 .getProductWith (Polynomial<SampleType> ({ coeffs[0], coeffs[1], coeffs[2] }));\r
+ denominator1 = denominator1.getProductWith (Polynomial<SampleType> ({ one, coeffs[3], coeffs[4] }));\r
}\r
}\r
\r
\r
if (i->getFilterOrder() == 1)\r
{\r
- numerator2 = numerator2.getProductWith (dsp::Polynomial<SampleType> ({ coeffs[0], coeffs[1] }));\r
- denominator2 = denominator2.getProductWith (dsp::Polynomial<SampleType> ({ one, coeffs[2] }));\r
+ numerator2 = numerator2 .getProductWith (Polynomial<SampleType> ({ coeffs[0], coeffs[1] }));\r
+ denominator2 = denominator2.getProductWith (Polynomial<SampleType> ({ one, coeffs[2] }));\r
}\r
else\r
{\r
- numerator2 = numerator2.getProductWith (dsp::Polynomial<SampleType> ({ coeffs[0], coeffs[1], coeffs[2] }));\r
- denominator2 = denominator2.getProductWith (dsp::Polynomial<SampleType> ({ one, coeffs[3], coeffs[4] }));\r
+ numerator2 = numerator2 .getProductWith (Polynomial<SampleType> ({ coeffs[0], coeffs[1], coeffs[2] }));\r
+ denominator2 = denominator2.getProductWith (Polynomial<SampleType> ({ one, coeffs[3], coeffs[4] }));\r
}\r
}\r
\r
auto numerator = numeratorf1.getSumWith (numeratorf2);\r
auto denominator = denominator1.getProductWith (denominator2);\r
\r
- dsp::IIR::Coefficients<SampleType> coeffs;\r
+ IIR::Coefficients<SampleType> coeffs;\r
\r
coeffs.coefficients.clear();\r
auto inversion = one / denominator[0];\r
}\r
\r
template <typename SampleType>\r
-typename dsp::AudioBlock<SampleType> Oversampling<SampleType>::processSamplesUp (const dsp::AudioBlock<SampleType>& inputBlock) noexcept\r
+AudioBlock<SampleType> Oversampling<SampleType>::processSamplesUp (const AudioBlock<const SampleType>& inputBlock) noexcept\r
{\r
jassert (! stages.isEmpty());\r
\r
if (! isReady)\r
return {};\r
\r
- auto audioBlock = inputBlock;\r
+ auto* firstStage = stages.getUnchecked (0);\r
+ firstStage->processSamplesUp (inputBlock);\r
+ auto block = firstStage->getProcessedSamples (inputBlock.getNumSamples() * firstStage->factor);\r
\r
- for (auto* stage : stages)\r
+ for (int i = 1; i < stages.size(); ++i)\r
{\r
- stage->processSamplesUp (audioBlock);\r
- audioBlock = stage->getProcessedSamples (audioBlock.getNumSamples() * stage->factor);\r
+ stages[i]->processSamplesUp (block);\r
+ block = stages[i]->getProcessedSamples (block.getNumSamples() * stages[i]->factor);\r
}\r
\r
- return audioBlock;\r
+ return block;\r
}\r
\r
template <typename SampleType>\r
-void Oversampling<SampleType>::processSamplesDown (dsp::AudioBlock<SampleType>& outputBlock) noexcept\r
+void Oversampling<SampleType>::processSamplesDown (AudioBlock<SampleType>& outputBlock) noexcept\r
{\r
jassert (! stages.isEmpty());\r
\r
Don't forget to set the sample rate of that processing to N times the original\r
sample rate.\r
*/\r
- dsp::AudioBlock<SampleType> processSamplesUp (const dsp::AudioBlock<SampleType>& inputBlock) noexcept;\r
+ AudioBlock<SampleType> processSamplesUp (const AudioBlock<const SampleType>& inputBlock) noexcept;\r
\r
/** Must be called to perform the downsampling, after the upsampling and the\r
non-linear processing. The output signal is probably delayed by the internal\r
latency of the whole oversampling behaviour, so don't forget to take this\r
into account.\r
*/\r
- void processSamplesDown (dsp::AudioBlock<SampleType>& outputBlock) noexcept;\r
+ void processSamplesDown (AudioBlock<SampleType>& outputBlock) noexcept;\r
\r
//==============================================================================\r
/** Adds a new oversampling stage to the Oversampling class, multiplying the\r
//==============================================================================\r
ActionBroadcaster::ActionBroadcaster()\r
{\r
- // are you trying to create this object before or after juce has been intialised??\r
+ // are you trying to create this object before or after juce has been initialised??\r
JUCE_ASSERT_MESSAGE_MANAGER_EXISTS\r
}\r
\r
namespace juce\r
{\r
\r
+#if JUCE_ANDROID\r
+ extern void acquireMulticastLock();\r
+ extern void releaseMulticastLock();\r
+#endif\r
+\r
NetworkServiceDiscovery::Advertiser::Advertiser (const String& serviceTypeUID,\r
const String& serviceDescription,\r
int broadcastPortToUse, int connectionPort,\r
NetworkServiceDiscovery::AvailableServiceList::AvailableServiceList (const String& serviceType, int broadcastPort)\r
: Thread ("Discovery_listen"), serviceTypeUID (serviceType)\r
{\r
+ #if JUCE_ANDROID\r
+ acquireMulticastLock();\r
+ #endif\r
+\r
socket.bindToPort (broadcastPort);\r
startThread (2);\r
}\r
{\r
socket.shutdown();\r
stopThread (2000);\r
+\r
+ #if JUCE_ANDROID\r
+ releaseMulticastLock();\r
+ #endif\r
}\r
\r
void NetworkServiceDiscovery::AvailableServiceList::run()\r
Contains classes that implement a simple protocol for broadcasting the availability\r
and location of a discoverable service on the local network, and for maintaining a\r
list of known services.\r
+\r
+ @tags{Events}\r
*/\r
struct NetworkServiceDiscovery\r
{\r
\r
To use, simply create an instance of an Advertiser and it'll broadcast until\r
you delete it.\r
+\r
+ @tags{Events}\r
*/\r
struct Advertiser : private Thread\r
{\r
//==============================================================================\r
/**\r
Contains information about a service that has been found on the network.\r
+\r
@see AvailableServiceList, Advertiser\r
+\r
+ @tags{Events}\r
*/\r
struct Service\r
{\r
Just create an instance of AvailableServiceList and it will start listening - you\r
can register a callback with its onChange member to find out when services\r
appear/disappear, and you can call getServices() to find out the current list.\r
+\r
@see Service, Advertiser\r
+\r
+ @tags{Events}\r
*/\r
struct AvailableServiceList : private Thread,\r
private AsyncUpdater\r
/** Destructor */\r
~AvailableServiceList() override;\r
\r
- /** A lambda that can be set to recieve a callback when the list changes */\r
+ /** A lambda that can be set to receive a callback when the list changes */\r
std::function<void()> onChange;\r
\r
/** Returns a list of the currently known services. */\r
==============================================================================\r
*/\r
\r
+\r
/*******************************************************************************\r
The block below describes the properties of this module, and is read by\r
the Projucer to automatically generate project code that uses it.\r
\r
BEGIN_JUCE_MODULE_DECLARATION\r
\r
- ID: juce_events\r
- vendor: juce\r
- version: 5.4.5\r
- name: JUCE message and event handling classes\r
- description: Classes for running an application's main event loop and sending/receiving messages, timers, etc.\r
- website: http://www.juce.com/juce\r
- license: ISC\r
+ ID: juce_events\r
+ vendor: juce\r
+ version: 5.4.6\r
+ name: JUCE message and event handling classes\r
+ description: Classes for running an application's main event loop and sending/receiving messages, timers, etc.\r
+ website: http://www.juce.com/juce\r
+ license: ISC\r
\r
- dependencies: juce_core\r
+ dependencies: juce_core\r
\r
END_JUCE_MODULE_DECLARATION\r
\r
#include <juce_core/juce_core.h>\r
\r
//==============================================================================\r
-/** Config: JUCE_EXECUTE_APP_SUSPEND_ON_IOS_BACKGROUND_TASK\r
+/** Config: JUCE_EXECUTE_APP_SUSPEND_ON_BACKGROUND_TASK\r
Will execute your application's suspend method on an iOS background task, giving\r
you extra time to save your applications state.\r
*/\r
\r
MessageListener::MessageListener() noexcept\r
{\r
- // Are you trying to create a messagelistener before or after juce has been intialised??\r
+ // Are you trying to create a messagelistener before or after juce has been initialised??\r
JUCE_ASSERT_MESSAGE_MANAGER_EXISTS\r
}\r
\r
If another thread is currently using the MessageManager, this will wait until that\r
thread releases the lock to the MessageManager.\r
\r
- This call will only exit if the lock was accquired by this thread. Calling abort while\r
+ This call will only exit if the lock was acquired by this thread. Calling abort while\r
a thread is waiting for enter to finish, will have no effect.\r
\r
@see exit, abort\r
*/\r
void enter() const noexcept;\r
\r
- /** Attempts to lock the meesage manager and exits if abort is called.\r
+ /** Attempts to lock the message manager and exits if abort is called.\r
\r
This method behaves identically to enter, except that it will abort waiting for\r
the lock if the abort method is called.\r
messageManagerLock.abort();\r
}\r
\r
- @returns false if waiting for a lock was aborted, true if the lock was accquired.\r
+ @returns false if waiting for a lock was aborted, true if the lock was acquired.\r
@see enter, abort, ScopedTryLock\r
*/\r
bool tryEnter() const noexcept;\r
/** Unblocks a thread which is waiting in tryEnter\r
Call this method if you want to unblock a thread which is waiting for the\r
MessageManager lock in tryEnter.\r
- This method does not have any effetc on a thread waiting for a lock in enter.\r
+ This method does not have any effect on a thread waiting for a lock in enter.\r
@see tryEnter\r
*/\r
void abort() const noexcept;\r
for (;;)\r
{\r
if (LinuxErrorHandling::keyboardBreakOccurred)\r
- JUCEApplicationBase::getInstance()->quit();\r
+ JUCEApplicationBase::quit();\r
\r
if (auto* runLoop = InternalRunLoop::getInstanceWithoutCreating())\r
{\r
\r
extern HWND juce_messageWindowHandle;\r
\r
+#if JUCE_MODULE_AVAILABLE_juce_audio_plugin_client && JucePlugin_Build_Unity\r
+ bool juce_isRunningInUnity();\r
+#endif\r
+\r
+#if JUCE_MODULE_AVAILABLE_juce_gui_extra\r
+ LRESULT juce_offerEventToActiveXControl (::MSG&);\r
+#endif\r
+\r
using CheckEventBlockedByModalComps = bool (*)(const MSG&);\r
CheckEventBlockedByModalComps isEventBlockedByModalComps = nullptr;\r
\r
using SettingChangeCallbackFunc = void (*)(void);\r
SettingChangeCallbackFunc settingChangeCallback = nullptr;\r
\r
-#if JUCE_MODULE_AVAILABLE_juce_audio_plugin_client && JucePlugin_Build_Unity\r
- bool juce_isRunningInUnity();\r
-#endif\r
-\r
//==============================================================================\r
-namespace WindowsMessageHelpers\r
+class InternalMessageQueue\r
{\r
- const unsigned int customMessageID = WM_USER + 123;\r
- const unsigned int broadcastMessageMagicNumber = 0xc403;\r
+public:\r
+ InternalMessageQueue()\r
+ {\r
+ messageWindow = std::make_unique<HiddenMessageWindow> (messageWindowName, (WNDPROC) messageWndProc);\r
+ juce_messageWindowHandle = messageWindow->getHWND();\r
+ }\r
\r
- const TCHAR messageWindowName[] = _T("JUCEWindow");\r
- std::unique_ptr<HiddenMessageWindow> messageWindow;\r
+ ~InternalMessageQueue()\r
+ {\r
+ juce_messageWindowHandle = 0;\r
+ clearSingletonInstance();\r
+ }\r
+\r
+ JUCE_DECLARE_SINGLETON (InternalMessageQueue, false)\r
\r
- void dispatchMessageFromLParam (LPARAM lParam)\r
+ //==============================================================================\r
+ void broadcastMessage (const String& message)\r
{\r
- if (auto message = reinterpret_cast<MessageManager::MessageBase*> (lParam))\r
- {\r
- JUCE_TRY\r
- {\r
- message->messageCallback();\r
- }\r
- JUCE_CATCH_EXCEPTION\r
+ auto localCopy = message;\r
\r
- message->decReferenceCount();\r
+ Array<HWND> windows;\r
+ EnumWindows (&broadcastEnumWindowProc, (LPARAM) &windows);\r
+\r
+ for (int i = windows.size(); --i >= 0;)\r
+ {\r
+ COPYDATASTRUCT data;\r
+ data.dwData = broadcastMessageMagicNumber;\r
+ data.cbData = (localCopy.length() + 1) * sizeof (CharPointer_UTF32::CharType);\r
+ data.lpData = (void*) localCopy.toUTF32().getAddress();\r
+\r
+ DWORD_PTR result;\r
+ SendMessageTimeout (windows.getUnchecked (i), WM_COPYDATA,\r
+ (WPARAM) juce_messageWindowHandle,\r
+ (LPARAM) &data,\r
+ SMTO_BLOCK | SMTO_ABORTIFHUNG, 8000, &result);\r
}\r
}\r
\r
- BOOL CALLBACK broadcastEnumWindowProc (HWND hwnd, LPARAM lParam)\r
+ void postMessage (MessageManager::MessageBase* message)\r
{\r
- if (hwnd != juce_messageWindowHandle)\r
+ bool shouldTriggerMessageQueueDispatch = false;\r
+\r
{\r
- TCHAR windowName[64] = { 0 }; // no need to read longer strings than this\r
- GetWindowText (hwnd, windowName, 63);\r
+ const ScopedLock sl (lock);\r
\r
- if (String (windowName) == messageWindowName)\r
- reinterpret_cast<Array<HWND>*> (lParam)->add (hwnd);\r
+ shouldTriggerMessageQueueDispatch = messageQueue.isEmpty();\r
+ messageQueue.add (message);\r
}\r
\r
- return TRUE;\r
+ if (! shouldTriggerMessageQueueDispatch)\r
+ return;\r
+\r
+ #if JUCE_MODULE_AVAILABLE_juce_audio_plugin_client && JucePlugin_Build_Unity\r
+ if (juce_isRunningInUnity())\r
+ {\r
+ SendNotifyMessage (juce_messageWindowHandle, customMessageID, 0, 0);\r
+ return;\r
+ }\r
+ #endif\r
+\r
+ PostMessage (juce_messageWindowHandle, customMessageID, 0, 0);\r
}\r
\r
- void handleBroadcastMessage (const COPYDATASTRUCT* data)\r
+ bool dispatchNextMessage (bool returnIfNoPendingMessages)\r
{\r
- if (data != nullptr && data->dwData == broadcastMessageMagicNumber)\r
- {\r
- struct BroadcastMessage : public CallbackMessage\r
- {\r
- BroadcastMessage (CharPointer_UTF32 text, size_t length) : message (text, length) {}\r
- void messageCallback() override { MessageManager::getInstance()->deliverBroadcastMessage (message); }\r
+ MSG m;\r
\r
- String message;\r
- };\r
+ if (returnIfNoPendingMessages && ! PeekMessage (&m, (HWND) 0, 0, 0, PM_NOREMOVE))\r
+ return false;\r
\r
- (new BroadcastMessage (CharPointer_UTF32 ((const CharPointer_UTF32::CharType*) data->lpData),\r
- data->cbData / sizeof (CharPointer_UTF32::CharType)))\r
- ->post();\r
+ if (GetMessage (&m, (HWND) 0, 0, 0) >= 0)\r
+ {\r
+ #if JUCE_MODULE_AVAILABLE_juce_gui_extra\r
+ if (juce_offerEventToActiveXControl (m) != S_FALSE)\r
+ return true;\r
+ #endif\r
+\r
+ if (m.message == customMessageID && m.hwnd == juce_messageWindowHandle)\r
+ {\r
+ dispatchMessages();\r
+ }\r
+ else if (m.message == WM_QUIT)\r
+ {\r
+ if (auto* app = JUCEApplicationBase::getInstance())\r
+ app->systemRequestedQuit();\r
+ }\r
+ else if (isEventBlockedByModalComps == nullptr || ! isEventBlockedByModalComps (m))\r
+ {\r
+ if ((m.message == WM_LBUTTONDOWN || m.message == WM_RBUTTONDOWN)\r
+ && ! JuceWindowIdentifier::isJUCEWindow (m.hwnd))\r
+ {\r
+ // if it's someone else's window being clicked on, and the focus is\r
+ // currently on a juce window, pass the kb focus over..\r
+ auto currentFocus = GetFocus();\r
+\r
+ if (currentFocus == 0 || JuceWindowIdentifier::isJUCEWindow (currentFocus))\r
+ SetFocus (m.hwnd);\r
+ }\r
+\r
+ TranslateMessage (&m);\r
+ DispatchMessage (&m);\r
+ }\r
}\r
+\r
+ return true;\r
}\r
\r
+private:\r
//==============================================================================\r
- LRESULT CALLBACK messageWndProc (HWND h, UINT message, WPARAM wParam, LPARAM lParam) noexcept\r
+ static LRESULT CALLBACK messageWndProc (HWND h, UINT message, WPARAM wParam, LPARAM lParam) noexcept\r
{\r
if (h == juce_messageWindowHandle)\r
{\r
if (message == customMessageID)\r
{\r
- // (These are trapped early in our dispatch loop, but must also be checked\r
- // here in case some 3rd-party code is running the dispatch loop).\r
- dispatchMessageFromLParam (lParam);\r
+ if (auto* queue = InternalMessageQueue::getInstanceWithoutCreating())\r
+ queue->dispatchMessages();\r
+\r
return 0;\r
}\r
\r
\r
return DefWindowProc (h, message, wParam, lParam);\r
}\r
-}\r
\r
-#if JUCE_MODULE_AVAILABLE_juce_gui_extra\r
-LRESULT juce_offerEventToActiveXControl (::MSG&);\r
-#endif\r
+ static BOOL CALLBACK broadcastEnumWindowProc (HWND hwnd, LPARAM lParam)\r
+ {\r
+ if (hwnd != juce_messageWindowHandle)\r
+ {\r
+ TCHAR windowName[64] = { 0 }; // no need to read longer strings than this\r
+ GetWindowText (hwnd, windowName, 63);\r
\r
-//==============================================================================\r
-bool MessageManager::dispatchNextMessageOnSystemQueue (bool returnIfNoPendingMessages)\r
-{\r
- using namespace WindowsMessageHelpers;\r
- MSG m;\r
+ if (String (windowName) == messageWindowName)\r
+ reinterpret_cast<Array<HWND>*> (lParam)->add (hwnd);\r
+ }\r
\r
- if (returnIfNoPendingMessages && ! PeekMessage (&m, (HWND) 0, 0, 0, PM_NOREMOVE))\r
- return false;\r
+ return TRUE;\r
+ }\r
\r
- if (GetMessage (&m, (HWND) 0, 0, 0) >= 0)\r
+ static void dispatchMessage (MessageManager::MessageBase* message)\r
{\r
- #if JUCE_MODULE_AVAILABLE_juce_gui_extra\r
- if (juce_offerEventToActiveXControl (m) != S_FALSE)\r
- return true;\r
- #endif\r
-\r
- if (m.message == customMessageID && m.hwnd == juce_messageWindowHandle)\r
+ JUCE_TRY\r
{\r
- dispatchMessageFromLParam (m.lParam);\r
+ message->messageCallback();\r
}\r
- else if (m.message == WM_QUIT)\r
+ JUCE_CATCH_EXCEPTION\r
+\r
+ message->decReferenceCount();\r
+ }\r
+\r
+ static void handleBroadcastMessage (const COPYDATASTRUCT* data)\r
+ {\r
+ if (data != nullptr && data->dwData == broadcastMessageMagicNumber)\r
{\r
- if (auto* app = JUCEApplicationBase::getInstance())\r
- app->systemRequestedQuit();\r
+ struct BroadcastMessage : public CallbackMessage\r
+ {\r
+ BroadcastMessage (CharPointer_UTF32 text, size_t length) : message (text, length) {}\r
+ void messageCallback() override { MessageManager::getInstance()->deliverBroadcastMessage (message); }\r
+\r
+ String message;\r
+ };\r
+\r
+ (new BroadcastMessage (CharPointer_UTF32 ((const CharPointer_UTF32::CharType*) data->lpData),\r
+ data->cbData / sizeof (CharPointer_UTF32::CharType)))\r
+ ->post();\r
}\r
- else if (isEventBlockedByModalComps == nullptr || ! isEventBlockedByModalComps (m))\r
+ }\r
+\r
+ void dispatchMessages()\r
+ {\r
+ ReferenceCountedArray<MessageManager::MessageBase> messagesToDispatch;\r
+\r
{\r
- if ((m.message == WM_LBUTTONDOWN || m.message == WM_RBUTTONDOWN)\r
- && ! JuceWindowIdentifier::isJUCEWindow (m.hwnd))\r
- {\r
- // if it's someone else's window being clicked on, and the focus is\r
- // currently on a juce window, pass the kb focus over..\r
- auto currentFocus = GetFocus();\r
+ const ScopedLock sl (lock);\r
\r
- if (currentFocus == 0 || JuceWindowIdentifier::isJUCEWindow (currentFocus))\r
- SetFocus (m.hwnd);\r
- }\r
+ if (messageQueue.isEmpty())\r
+ return;\r
\r
- TranslateMessage (&m);\r
- DispatchMessage (&m);\r
+ messagesToDispatch.swapWith (messageQueue);\r
+ }\r
+\r
+ for (int i = 0; i < messagesToDispatch.size(); ++i)\r
+ {\r
+ auto message = messagesToDispatch.getUnchecked (i);\r
+ message->incReferenceCount();\r
+ dispatchMessage (message.get());\r
}\r
}\r
\r
- return true;\r
-}\r
+ //==============================================================================\r
+ static constexpr unsigned int customMessageID = WM_USER + 123;\r
+ static constexpr unsigned int broadcastMessageMagicNumber = 0xc403;\r
+ static const TCHAR messageWindowName[];\r
\r
-bool MessageManager::postMessageToSystemQueue (MessageManager::MessageBase* const message)\r
-{\r
- message->incReferenceCount();\r
+ std::unique_ptr<HiddenMessageWindow> messageWindow;\r
\r
- #if JUCE_MODULE_AVAILABLE_juce_audio_plugin_client && JucePlugin_Build_Unity\r
- if (juce_isRunningInUnity())\r
- return SendNotifyMessage (juce_messageWindowHandle, WindowsMessageHelpers::customMessageID, 0, (LPARAM) message) != 0;\r
- #endif\r
+ CriticalSection lock;\r
+ ReferenceCountedArray<MessageManager::MessageBase> messageQueue;\r
\r
- return PostMessage (juce_messageWindowHandle, WindowsMessageHelpers::customMessageID, 0, (LPARAM) message) != 0;\r
-}\r
+ //==============================================================================\r
+ JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (InternalMessageQueue)\r
+};\r
\r
-void MessageManager::broadcastMessage (const String& value)\r
+JUCE_IMPLEMENT_SINGLETON (InternalMessageQueue)\r
+\r
+const TCHAR InternalMessageQueue::messageWindowName[] = _T("JUCEWindow");\r
+\r
+//==============================================================================\r
+bool MessageManager::dispatchNextMessageOnSystemQueue (bool returnIfNoPendingMessages)\r
{\r
- auto localCopy = value;\r
+ if (auto* queue = InternalMessageQueue::getInstanceWithoutCreating())\r
+ return queue->dispatchNextMessage (returnIfNoPendingMessages);\r
\r
- Array<HWND> windows;\r
- EnumWindows (&WindowsMessageHelpers::broadcastEnumWindowProc, (LPARAM) &windows);\r
+ return false;\r
+}\r
\r
- for (int i = windows.size(); --i >= 0;)\r
+bool MessageManager::postMessageToSystemQueue (MessageManager::MessageBase* const message)\r
+{\r
+ if (auto* queue = InternalMessageQueue::getInstanceWithoutCreating())\r
{\r
- COPYDATASTRUCT data;\r
- data.dwData = WindowsMessageHelpers::broadcastMessageMagicNumber;\r
- data.cbData = (localCopy.length() + 1) * sizeof (CharPointer_UTF32::CharType);\r
- data.lpData = (void*) localCopy.toUTF32().getAddress();\r
-\r
- DWORD_PTR result;\r
- SendMessageTimeout (windows.getUnchecked (i), WM_COPYDATA,\r
- (WPARAM) juce_messageWindowHandle,\r
- (LPARAM) &data,\r
- SMTO_BLOCK | SMTO_ABORTIFHUNG, 8000, &result);\r
+ queue->postMessage (message);\r
+ return true;\r
}\r
+\r
+ return false;\r
+}\r
+\r
+void MessageManager::broadcastMessage (const String& value)\r
+{\r
+ if (auto* queue = InternalMessageQueue::getInstanceWithoutCreating())\r
+ queue->broadcastMessage (value);\r
}\r
\r
//==============================================================================\r
void MessageManager::doPlatformSpecificInitialisation()\r
{\r
OleInitialize (0);\r
-\r
- using namespace WindowsMessageHelpers;\r
- messageWindow.reset (new HiddenMessageWindow (messageWindowName, (WNDPROC) messageWndProc));\r
- juce_messageWindowHandle = messageWindow->getHWND();\r
+ InternalMessageQueue::getInstance();\r
}\r
\r
void MessageManager::doPlatformSpecificShutdown()\r
{\r
- WindowsMessageHelpers::messageWindow = nullptr;\r
-\r
+ InternalMessageQueue::deleteInstance();\r
OleUninitialize();\r
}\r
\r
*/\r
Colour withBrightness (float newBrightness) const noexcept;\r
\r
- /** Returns a copy of this colour with it hue rotated.\r
+ /** Returns a copy of this colour with its hue rotated.\r
The new colour's hue is ((this->getHue() + amountToRotate) % 1.0)\r
@see brighter, darker, withMultipliedBrightness\r
*/\r
namespace juce\r
{\r
\r
-const Colour Colours::transparentBlack (0);\r
-const Colour Colours::transparentWhite (0x00ffffff);\r
-\r
-const Colour Colours::aliceblue (0xfff0f8ff);\r
-const Colour Colours::antiquewhite (0xfffaebd7);\r
-const Colour Colours::aqua (0xff00ffff);\r
-const Colour Colours::aquamarine (0xff7fffd4);\r
-const Colour Colours::azure (0xfff0ffff);\r
-const Colour Colours::beige (0xfff5f5dc);\r
-const Colour Colours::bisque (0xffffe4c4);\r
-const Colour Colours::black (0xff000000);\r
-const Colour Colours::blanchedalmond (0xffffebcd);\r
-const Colour Colours::blue (0xff0000ff);\r
-const Colour Colours::blueviolet (0xff8a2be2);\r
-const Colour Colours::brown (0xffa52a2a);\r
-const Colour Colours::burlywood (0xffdeb887);\r
-const Colour Colours::cadetblue (0xff5f9ea0);\r
-const Colour Colours::chartreuse (0xff7fff00);\r
-const Colour Colours::chocolate (0xffd2691e);\r
-const Colour Colours::coral (0xffff7f50);\r
-const Colour Colours::cornflowerblue (0xff6495ed);\r
-const Colour Colours::cornsilk (0xfffff8dc);\r
-const Colour Colours::crimson (0xffdc143c);\r
-const Colour Colours::cyan (0xff00ffff);\r
-const Colour Colours::darkblue (0xff00008b);\r
-const Colour Colours::darkcyan (0xff008b8b);\r
-const Colour Colours::darkgoldenrod (0xffb8860b);\r
-const Colour Colours::darkgrey (0xff555555);\r
-const Colour Colours::darkgreen (0xff006400);\r
-const Colour Colours::darkkhaki (0xffbdb76b);\r
-const Colour Colours::darkmagenta (0xff8b008b);\r
-const Colour Colours::darkolivegreen (0xff556b2f);\r
-const Colour Colours::darkorange (0xffff8c00);\r
-const Colour Colours::darkorchid (0xff9932cc);\r
-const Colour Colours::darkred (0xff8b0000);\r
-const Colour Colours::darksalmon (0xffe9967a);\r
-const Colour Colours::darkseagreen (0xff8fbc8f);\r
-const Colour Colours::darkslateblue (0xff483d8b);\r
-const Colour Colours::darkslategrey (0xff2f4f4f);\r
-const Colour Colours::darkturquoise (0xff00ced1);\r
-const Colour Colours::darkviolet (0xff9400d3);\r
-const Colour Colours::deeppink (0xffff1493);\r
-const Colour Colours::deepskyblue (0xff00bfff);\r
-const Colour Colours::dimgrey (0xff696969);\r
-const Colour Colours::dodgerblue (0xff1e90ff);\r
-const Colour Colours::firebrick (0xffb22222);\r
-const Colour Colours::floralwhite (0xfffffaf0);\r
-const Colour Colours::forestgreen (0xff228b22);\r
-const Colour Colours::fuchsia (0xffff00ff);\r
-const Colour Colours::gainsboro (0xffdcdcdc);\r
-const Colour Colours::ghostwhite (0xfff8f8ff);\r
-const Colour Colours::gold (0xffffd700);\r
-const Colour Colours::goldenrod (0xffdaa520);\r
-const Colour Colours::grey (0xff808080);\r
-const Colour Colours::green (0xff008000);\r
-const Colour Colours::greenyellow (0xffadff2f);\r
-const Colour Colours::honeydew (0xfff0fff0);\r
-const Colour Colours::hotpink (0xffff69b4);\r
-const Colour Colours::indianred (0xffcd5c5c);\r
-const Colour Colours::indigo (0xff4b0082);\r
-const Colour Colours::ivory (0xfffffff0);\r
-const Colour Colours::khaki (0xfff0e68c);\r
-const Colour Colours::lavender (0xffe6e6fa);\r
-const Colour Colours::lavenderblush (0xfffff0f5);\r
-const Colour Colours::lawngreen (0xff7cfc00);\r
-const Colour Colours::lemonchiffon (0xfffffacd);\r
-const Colour Colours::lightblue (0xffadd8e6);\r
-const Colour Colours::lightcoral (0xfff08080);\r
-const Colour Colours::lightcyan (0xffe0ffff);\r
-const Colour Colours::lightgoldenrodyellow (0xfffafad2);\r
-const Colour Colours::lightgreen (0xff90ee90);\r
-const Colour Colours::lightgrey (0xffd3d3d3);\r
-const Colour Colours::lightpink (0xffffb6c1);\r
-const Colour Colours::lightsalmon (0xffffa07a);\r
-const Colour Colours::lightseagreen (0xff20b2aa);\r
-const Colour Colours::lightskyblue (0xff87cefa);\r
-const Colour Colours::lightslategrey (0xff778899);\r
-const Colour Colours::lightsteelblue (0xffb0c4de);\r
-const Colour Colours::lightyellow (0xffffffe0);\r
-const Colour Colours::lime (0xff00ff00);\r
-const Colour Colours::limegreen (0xff32cd32);\r
-const Colour Colours::linen (0xfffaf0e6);\r
-const Colour Colours::magenta (0xffff00ff);\r
-const Colour Colours::maroon (0xff800000);\r
-const Colour Colours::mediumaquamarine (0xff66cdaa);\r
-const Colour Colours::mediumblue (0xff0000cd);\r
-const Colour Colours::mediumorchid (0xffba55d3);\r
-const Colour Colours::mediumpurple (0xff9370db);\r
-const Colour Colours::mediumseagreen (0xff3cb371);\r
-const Colour Colours::mediumslateblue (0xff7b68ee);\r
-const Colour Colours::mediumspringgreen (0xff00fa9a);\r
-const Colour Colours::mediumturquoise (0xff48d1cc);\r
-const Colour Colours::mediumvioletred (0xffc71585);\r
-const Colour Colours::midnightblue (0xff191970);\r
-const Colour Colours::mintcream (0xfff5fffa);\r
-const Colour Colours::mistyrose (0xffffe4e1);\r
-const Colour Colours::moccasin (0xffffe4b5);\r
-const Colour Colours::navajowhite (0xffffdead);\r
-const Colour Colours::navy (0xff000080);\r
-const Colour Colours::oldlace (0xfffdf5e6);\r
-const Colour Colours::olive (0xff808000);\r
-const Colour Colours::olivedrab (0xff6b8e23);\r
-const Colour Colours::orange (0xffffa500);\r
-const Colour Colours::orangered (0xffff4500);\r
-const Colour Colours::orchid (0xffda70d6);\r
-const Colour Colours::palegoldenrod (0xffeee8aa);\r
-const Colour Colours::palegreen (0xff98fb98);\r
-const Colour Colours::paleturquoise (0xffafeeee);\r
-const Colour Colours::palevioletred (0xffdb7093);\r
-const Colour Colours::papayawhip (0xffffefd5);\r
-const Colour Colours::peachpuff (0xffffdab9);\r
-const Colour Colours::peru (0xffcd853f);\r
-const Colour Colours::pink (0xffffc0cb);\r
-const Colour Colours::plum (0xffdda0dd);\r
-const Colour Colours::powderblue (0xffb0e0e6);\r
-const Colour Colours::purple (0xff800080);\r
-const Colour Colours::rebeccapurple (0xff663399);\r
-const Colour Colours::red (0xffff0000);\r
-const Colour Colours::rosybrown (0xffbc8f8f);\r
-const Colour Colours::royalblue (0xff4169e1);\r
-const Colour Colours::saddlebrown (0xff8b4513);\r
-const Colour Colours::salmon (0xfffa8072);\r
-const Colour Colours::sandybrown (0xfff4a460);\r
-const Colour Colours::seagreen (0xff2e8b57);\r
-const Colour Colours::seashell (0xfffff5ee);\r
-const Colour Colours::sienna (0xffa0522d);\r
-const Colour Colours::silver (0xffc0c0c0);\r
-const Colour Colours::skyblue (0xff87ceeb);\r
-const Colour Colours::slateblue (0xff6a5acd);\r
-const Colour Colours::slategrey (0xff708090);\r
-const Colour Colours::snow (0xfffffafa);\r
-const Colour Colours::springgreen (0xff00ff7f);\r
-const Colour Colours::steelblue (0xff4682b4);\r
-const Colour Colours::tan (0xffd2b48c);\r
-const Colour Colours::teal (0xff008080);\r
-const Colour Colours::thistle (0xffd8bfd8);\r
-const Colour Colours::tomato (0xffff6347);\r
-const Colour Colours::turquoise (0xff40e0d0);\r
-const Colour Colours::violet (0xffee82ee);\r
-const Colour Colours::wheat (0xfff5deb3);\r
-const Colour Colours::white (0xffffffff);\r
-const Colour Colours::whitesmoke (0xfff5f5f5);\r
-const Colour Colours::yellow (0xffffff00);\r
-const Colour Colours::yellowgreen (0xff9acd32);\r
-\r
//==============================================================================\r
Colour Colours::findColourForName (const String& colourName,\r
Colour defaultColour)\r
{\r
- static const uint32 presets[] =\r
- {\r
- // (first value is the string's hashcode, second is ARGB)\r
+ struct StringHashAndColour { uint32 stringHash, colour; };\r
\r
- 0x05978fff, 0xff000000, /* black */\r
- 0x06bdcc29, 0xffffffff, /* white */\r
- 0x002e305a, 0xff0000ff, /* blue */\r
- 0x00308adf, 0xff808080, /* grey */\r
- 0x05e0cf03, 0xff008000, /* green */\r
- 0x0001b891, 0xffff0000, /* red */\r
- 0xd43c6474, 0xffffff00, /* yellow */\r
- 0x620886da, 0xfff0f8ff, /* aliceblue */\r
- 0x20a2676a, 0xfffaebd7, /* antiquewhite */\r
- 0x002dcebc, 0xff00ffff, /* aqua */\r
- 0x46bb5f7e, 0xff7fffd4, /* aquamarine */\r
- 0x0590228f, 0xfff0ffff, /* azure */\r
- 0x05947fe4, 0xfff5f5dc, /* beige */\r
- 0xad388e35, 0xffffe4c4, /* bisque */\r
- 0x00674f7e, 0xffffebcd, /* blanchedalmond */\r
- 0x39129959, 0xff8a2be2, /* blueviolet */\r
- 0x059a8136, 0xffa52a2a, /* brown */\r
- 0x89cea8f9, 0xffdeb887, /* burlywood */\r
- 0x0fa260cf, 0xff5f9ea0, /* cadetblue */\r
- 0x6b748956, 0xff7fff00, /* chartreuse */\r
- 0x2903623c, 0xffd2691e, /* chocolate */\r
- 0x05a74431, 0xffff7f50, /* coral */\r
- 0x618d42dd, 0xff6495ed, /* cornflowerblue */\r
- 0xe4b479fd, 0xfffff8dc, /* cornsilk */\r
- 0x3d8c4edf, 0xffdc143c, /* crimson */\r
- 0x002ed323, 0xff00ffff, /* cyan */\r
- 0x67cc74d0, 0xff00008b, /* darkblue */\r
- 0x67cd1799, 0xff008b8b, /* darkcyan */\r
- 0x31bbd168, 0xffb8860b, /* darkgoldenrod */\r
- 0x67cecf55, 0xff555555, /* darkgrey */\r
- 0x920b194d, 0xff006400, /* darkgreen */\r
- 0x923edd4c, 0xffbdb76b, /* darkkhaki */\r
- 0x5c293873, 0xff8b008b, /* darkmagenta */\r
- 0x6b6671fe, 0xff556b2f, /* darkolivegreen */\r
- 0xbcfd2524, 0xffff8c00, /* darkorange */\r
- 0xbcfdf799, 0xff9932cc, /* darkorchid */\r
- 0x55ee0d5b, 0xff8b0000, /* darkred */\r
- 0xc2e5f564, 0xffe9967a, /* darksalmon */\r
- 0x61be858a, 0xff8fbc8f, /* darkseagreen */\r
- 0xc2b0f2bd, 0xff483d8b, /* darkslateblue */\r
- 0xc2b34d42, 0xff2f4f4f, /* darkslategrey */\r
- 0x7cf2b06b, 0xff00ced1, /* darkturquoise */\r
- 0xc8769375, 0xff9400d3, /* darkviolet */\r
- 0x25832862, 0xffff1493, /* deeppink */\r
- 0xfcad568f, 0xff00bfff, /* deepskyblue */\r
- 0x634c8b67, 0xff696969, /* dimgrey */\r
- 0x45c1ce55, 0xff1e90ff, /* dodgerblue */\r
- 0xef19e3cb, 0xffb22222, /* firebrick */\r
- 0xb852b195, 0xfffffaf0, /* floralwhite */\r
- 0xd086fd06, 0xff228b22, /* forestgreen */\r
- 0xe106b6d7, 0xffff00ff, /* fuchsia */\r
- 0x7880d61e, 0xffdcdcdc, /* gainsboro */\r
- 0x2018a2fa, 0xfff8f8ff, /* ghostwhite */\r
- 0x00308060, 0xffffd700, /* gold */\r
- 0xb3b3bc1e, 0xffdaa520, /* goldenrod */\r
- 0xbab8a537, 0xffadff2f, /* greenyellow */\r
- 0xe4cacafb, 0xfff0fff0, /* honeydew */\r
- 0x41892743, 0xffff69b4, /* hotpink */\r
- 0xd5796f1a, 0xffcd5c5c, /* indianred */\r
- 0xb969fed2, 0xff4b0082, /* indigo */\r
- 0x05fef6a9, 0xfffffff0, /* ivory */\r
- 0x06149302, 0xfff0e68c, /* khaki */\r
- 0xad5a05c7, 0xffe6e6fa, /* lavender */\r
- 0x7c4d5b99, 0xfffff0f5, /* lavenderblush */\r
- 0x41cc4377, 0xff7cfc00, /* lawngreen */\r
- 0x195756f0, 0xfffffacd, /* lemonchiffon */\r
- 0x28e4ea70, 0xffadd8e6, /* lightblue */\r
- 0xf3c7ccdb, 0xfff08080, /* lightcoral */\r
- 0x28e58d39, 0xffe0ffff, /* lightcyan */\r
- 0x21234e3c, 0xfffafad2, /* lightgoldenrodyellow */\r
- 0xf40157ad, 0xff90ee90, /* lightgreen */\r
- 0x28e744f5, 0xffd3d3d3, /* lightgrey */\r
- 0x28eb3b8c, 0xffffb6c1, /* lightpink */\r
- 0x9fb78304, 0xffffa07a, /* lightsalmon */\r
- 0x50632b2a, 0xff20b2aa, /* lightseagreen */\r
- 0x68fb7b25, 0xff87cefa, /* lightskyblue */\r
- 0xa8a35ba2, 0xff778899, /* lightslategrey */\r
- 0xa20d484f, 0xffb0c4de, /* lightsteelblue */\r
- 0xaa2cf10a, 0xffffffe0, /* lightyellow */\r
- 0x0032afd5, 0xff00ff00, /* lime */\r
- 0x607bbc4e, 0xff32cd32, /* limegreen */\r
- 0x06234efa, 0xfffaf0e6, /* linen */\r
- 0x316858a9, 0xffff00ff, /* magenta */\r
- 0xbf8ca470, 0xff800000, /* maroon */\r
- 0xbd58e0b3, 0xff66cdaa, /* mediumaquamarine */\r
- 0x967dfd4f, 0xff0000cd, /* mediumblue */\r
- 0x056f5c58, 0xffba55d3, /* mediumorchid */\r
- 0x07556b71, 0xff9370db, /* mediumpurple */\r
- 0x5369b689, 0xff3cb371, /* mediumseagreen */\r
- 0x066be19e, 0xff7b68ee, /* mediumslateblue */\r
- 0x3256b281, 0xff00fa9a, /* mediumspringgreen */\r
- 0xc0ad9f4c, 0xff48d1cc, /* mediumturquoise */\r
- 0x628e63dd, 0xffc71585, /* mediumvioletred */\r
- 0x168eb32a, 0xff191970, /* midnightblue */\r
- 0x4306b960, 0xfff5fffa, /* mintcream */\r
- 0x4cbc0e6b, 0xffffe4e1, /* mistyrose */\r
- 0xd9447d59, 0xffffe4b5, /* moccasin */\r
- 0xe97218a6, 0xffffdead, /* navajowhite */\r
- 0x00337bb6, 0xff000080, /* navy */\r
- 0xadd2d33e, 0xfffdf5e6, /* oldlace */\r
- 0x064ee1db, 0xff808000, /* olive */\r
- 0x9e33a98a, 0xff6b8e23, /* olivedrab */\r
- 0xc3de262e, 0xffffa500, /* orange */\r
- 0x58bebba3, 0xffff4500, /* orangered */\r
- 0xc3def8a3, 0xffda70d6, /* orchid */\r
- 0x28cb4834, 0xffeee8aa, /* palegoldenrod */\r
- 0x3d9dd619, 0xff98fb98, /* palegreen */\r
- 0x74022737, 0xffafeeee, /* paleturquoise */\r
- 0x15e2ebc8, 0xffdb7093, /* palevioletred */\r
- 0x5fd898e2, 0xffffefd5, /* papayawhip */\r
- 0x93e1b776, 0xffffdab9, /* peachpuff */\r
- 0x003472f8, 0xffcd853f, /* peru */\r
- 0x00348176, 0xffffc0cb, /* pink */\r
- 0x00348d94, 0xffdda0dd, /* plum */\r
- 0xd036be93, 0xffb0e0e6, /* powderblue */\r
- 0xc5c507bc, 0xff800080, /* purple */\r
- 0xf381f607, 0xff663399, /* rebeccapurple */\r
- 0xa89d65b3, 0xffbc8f8f, /* rosybrown */\r
- 0xbd9413e1, 0xff4169e1, /* royalblue */\r
- 0xf456044f, 0xff8b4513, /* saddlebrown */\r
- 0xc9c6f66e, 0xfffa8072, /* salmon */\r
- 0x0bb131e1, 0xfff4a460, /* sandybrown */\r
- 0x34636c14, 0xff2e8b57, /* seagreen */\r
- 0x3507fb41, 0xfffff5ee, /* seashell */\r
- 0xca348772, 0xffa0522d, /* sienna */\r
- 0xca37d30d, 0xffc0c0c0, /* silver */\r
- 0x80da74fb, 0xff87ceeb, /* skyblue */\r
- 0x44a8dd73, 0xff6a5acd, /* slateblue */\r
- 0x44ab37f8, 0xff708090, /* slategrey */\r
- 0x0035f183, 0xfffffafa, /* snow */\r
- 0xd5440d16, 0xff00ff7f, /* springgreen */\r
- 0x3e1524a5, 0xff4682b4, /* steelblue */\r
- 0x0001bfa1, 0xffd2b48c, /* tan */\r
- 0x0036425c, 0xff008080, /* teal */\r
- 0xafc8858f, 0xffd8bfd8, /* thistle */\r
- 0xcc41600a, 0xffff6347, /* tomato */\r
- 0xfeea9b21, 0xff40e0d0, /* turquoise */\r
- 0xcf57947f, 0xffee82ee, /* violet */\r
- 0x06bdbae7, 0xfff5deb3, /* wheat */\r
- 0x10802ee6, 0xfff5f5f5, /* whitesmoke */\r
- 0xe1b5130f, 0xff9acd32 /* yellowgreen */\r
+ static const StringHashAndColour presets[]\r
+ {\r
+ { 0x05978fff, 0xff000000 }, /* black */\r
+ { 0x06bdcc29, 0xffffffff }, /* white */\r
+ { 0x002e305a, 0xff0000ff }, /* blue */\r
+ { 0x00308adf, 0xff808080 }, /* grey */\r
+ { 0x05e0cf03, 0xff008000 }, /* green */\r
+ { 0x0001b891, 0xffff0000 }, /* red */\r
+ { 0xd43c6474, 0xffffff00 }, /* yellow */\r
+ { 0x620886da, 0xfff0f8ff }, /* aliceblue */\r
+ { 0x20a2676a, 0xfffaebd7 }, /* antiquewhite */\r
+ { 0x002dcebc, 0xff00ffff }, /* aqua */\r
+ { 0x46bb5f7e, 0xff7fffd4 }, /* aquamarine */\r
+ { 0x0590228f, 0xfff0ffff }, /* azure */\r
+ { 0x05947fe4, 0xfff5f5dc }, /* beige */\r
+ { 0xad388e35, 0xffffe4c4 }, /* bisque */\r
+ { 0x00674f7e, 0xffffebcd }, /* blanchedalmond */\r
+ { 0x39129959, 0xff8a2be2 }, /* blueviolet */\r
+ { 0x059a8136, 0xffa52a2a }, /* brown */\r
+ { 0x89cea8f9, 0xffdeb887 }, /* burlywood */\r
+ { 0x0fa260cf, 0xff5f9ea0 }, /* cadetblue */\r
+ { 0x6b748956, 0xff7fff00 }, /* chartreuse */\r
+ { 0x2903623c, 0xffd2691e }, /* chocolate */\r
+ { 0x05a74431, 0xffff7f50 }, /* coral */\r
+ { 0x618d42dd, 0xff6495ed }, /* cornflowerblue */\r
+ { 0xe4b479fd, 0xfffff8dc }, /* cornsilk */\r
+ { 0x3d8c4edf, 0xffdc143c }, /* crimson */\r
+ { 0x002ed323, 0xff00ffff }, /* cyan */\r
+ { 0x67cc74d0, 0xff00008b }, /* darkblue */\r
+ { 0x67cd1799, 0xff008b8b }, /* darkcyan */\r
+ { 0x31bbd168, 0xffb8860b }, /* darkgoldenrod */\r
+ { 0x67cecf55, 0xff555555 }, /* darkgrey */\r
+ { 0x920b194d, 0xff006400 }, /* darkgreen */\r
+ { 0x923edd4c, 0xffbdb76b }, /* darkkhaki */\r
+ { 0x5c293873, 0xff8b008b }, /* darkmagenta */\r
+ { 0x6b6671fe, 0xff556b2f }, /* darkolivegreen */\r
+ { 0xbcfd2524, 0xffff8c00 }, /* darkorange */\r
+ { 0xbcfdf799, 0xff9932cc }, /* darkorchid */\r
+ { 0x55ee0d5b, 0xff8b0000 }, /* darkred */\r
+ { 0xc2e5f564, 0xffe9967a }, /* darksalmon */\r
+ { 0x61be858a, 0xff8fbc8f }, /* darkseagreen */\r
+ { 0xc2b0f2bd, 0xff483d8b }, /* darkslateblue */\r
+ { 0xc2b34d42, 0xff2f4f4f }, /* darkslategrey */\r
+ { 0x7cf2b06b, 0xff00ced1 }, /* darkturquoise */\r
+ { 0xc8769375, 0xff9400d3 }, /* darkviolet */\r
+ { 0x25832862, 0xffff1493 }, /* deeppink */\r
+ { 0xfcad568f, 0xff00bfff }, /* deepskyblue */\r
+ { 0x634c8b67, 0xff696969 }, /* dimgrey */\r
+ { 0x45c1ce55, 0xff1e90ff }, /* dodgerblue */\r
+ { 0xef19e3cb, 0xffb22222 }, /* firebrick */\r
+ { 0xb852b195, 0xfffffaf0 }, /* floralwhite */\r
+ { 0xd086fd06, 0xff228b22 }, /* forestgreen */\r
+ { 0xe106b6d7, 0xffff00ff }, /* fuchsia */\r
+ { 0x7880d61e, 0xffdcdcdc }, /* gainsboro */\r
+ { 0x2018a2fa, 0xfff8f8ff }, /* ghostwhite */\r
+ { 0x00308060, 0xffffd700 }, /* gold */\r
+ { 0xb3b3bc1e, 0xffdaa520 }, /* goldenrod */\r
+ { 0xbab8a537, 0xffadff2f }, /* greenyellow */\r
+ { 0xe4cacafb, 0xfff0fff0 }, /* honeydew */\r
+ { 0x41892743, 0xffff69b4 }, /* hotpink */\r
+ { 0xd5796f1a, 0xffcd5c5c }, /* indianred */\r
+ { 0xb969fed2, 0xff4b0082 }, /* indigo */\r
+ { 0x05fef6a9, 0xfffffff0 }, /* ivory */\r
+ { 0x06149302, 0xfff0e68c }, /* khaki */\r
+ { 0xad5a05c7, 0xffe6e6fa }, /* lavender */\r
+ { 0x7c4d5b99, 0xfffff0f5 }, /* lavenderblush */\r
+ { 0x41cc4377, 0xff7cfc00 }, /* lawngreen */\r
+ { 0x195756f0, 0xfffffacd }, /* lemonchiffon */\r
+ { 0x28e4ea70, 0xffadd8e6 }, /* lightblue */\r
+ { 0xf3c7ccdb, 0xfff08080 }, /* lightcoral */\r
+ { 0x28e58d39, 0xffe0ffff }, /* lightcyan */\r
+ { 0x21234e3c, 0xfffafad2 }, /* lightgoldenrodyellow */\r
+ { 0xf40157ad, 0xff90ee90 }, /* lightgreen */\r
+ { 0x28e744f5, 0xffd3d3d3 }, /* lightgrey */\r
+ { 0x28eb3b8c, 0xffffb6c1 }, /* lightpink */\r
+ { 0x9fb78304, 0xffffa07a }, /* lightsalmon */\r
+ { 0x50632b2a, 0xff20b2aa }, /* lightseagreen */\r
+ { 0x68fb7b25, 0xff87cefa }, /* lightskyblue */\r
+ { 0xa8a35ba2, 0xff778899 }, /* lightslategrey */\r
+ { 0xa20d484f, 0xffb0c4de }, /* lightsteelblue */\r
+ { 0xaa2cf10a, 0xffffffe0 }, /* lightyellow */\r
+ { 0x0032afd5, 0xff00ff00 }, /* lime */\r
+ { 0x607bbc4e, 0xff32cd32 }, /* limegreen */\r
+ { 0x06234efa, 0xfffaf0e6 }, /* linen */\r
+ { 0x316858a9, 0xffff00ff }, /* magenta */\r
+ { 0xbf8ca470, 0xff800000 }, /* maroon */\r
+ { 0xbd58e0b3, 0xff66cdaa }, /* mediumaquamarine */\r
+ { 0x967dfd4f, 0xff0000cd }, /* mediumblue */\r
+ { 0x056f5c58, 0xffba55d3 }, /* mediumorchid */\r
+ { 0x07556b71, 0xff9370db }, /* mediumpurple */\r
+ { 0x5369b689, 0xff3cb371 }, /* mediumseagreen */\r
+ { 0x066be19e, 0xff7b68ee }, /* mediumslateblue */\r
+ { 0x3256b281, 0xff00fa9a }, /* mediumspringgreen */\r
+ { 0xc0ad9f4c, 0xff48d1cc }, /* mediumturquoise */\r
+ { 0x628e63dd, 0xffc71585 }, /* mediumvioletred */\r
+ { 0x168eb32a, 0xff191970 }, /* midnightblue */\r
+ { 0x4306b960, 0xfff5fffa }, /* mintcream */\r
+ { 0x4cbc0e6b, 0xffffe4e1 }, /* mistyrose */\r
+ { 0xd9447d59, 0xffffe4b5 }, /* moccasin */\r
+ { 0xe97218a6, 0xffffdead }, /* navajowhite */\r
+ { 0x00337bb6, 0xff000080 }, /* navy */\r
+ { 0xadd2d33e, 0xfffdf5e6 }, /* oldlace */\r
+ { 0x064ee1db, 0xff808000 }, /* olive */\r
+ { 0x9e33a98a, 0xff6b8e23 }, /* olivedrab */\r
+ { 0xc3de262e, 0xffffa500 }, /* orange */\r
+ { 0x58bebba3, 0xffff4500 }, /* orangered */\r
+ { 0xc3def8a3, 0xffda70d6 }, /* orchid */\r
+ { 0x28cb4834, 0xffeee8aa }, /* palegoldenrod */\r
+ { 0x3d9dd619, 0xff98fb98 }, /* palegreen */\r
+ { 0x74022737, 0xffafeeee }, /* paleturquoise */\r
+ { 0x15e2ebc8, 0xffdb7093 }, /* palevioletred */\r
+ { 0x5fd898e2, 0xffffefd5 }, /* papayawhip */\r
+ { 0x93e1b776, 0xffffdab9 }, /* peachpuff */\r
+ { 0x003472f8, 0xffcd853f }, /* peru */\r
+ { 0x00348176, 0xffffc0cb }, /* pink */\r
+ { 0x00348d94, 0xffdda0dd }, /* plum */\r
+ { 0xd036be93, 0xffb0e0e6 }, /* powderblue */\r
+ { 0xc5c507bc, 0xff800080 }, /* purple */\r
+ { 0xf381f607, 0xff663399 }, /* rebeccapurple */\r
+ { 0xa89d65b3, 0xffbc8f8f }, /* rosybrown */\r
+ { 0xbd9413e1, 0xff4169e1 }, /* royalblue */\r
+ { 0xf456044f, 0xff8b4513 }, /* saddlebrown */\r
+ { 0xc9c6f66e, 0xfffa8072 }, /* salmon */\r
+ { 0x0bb131e1, 0xfff4a460 }, /* sandybrown */\r
+ { 0x34636c14, 0xff2e8b57 }, /* seagreen */\r
+ { 0x3507fb41, 0xfffff5ee }, /* seashell */\r
+ { 0xca348772, 0xffa0522d }, /* sienna */\r
+ { 0xca37d30d, 0xffc0c0c0 }, /* silver */\r
+ { 0x80da74fb, 0xff87ceeb }, /* skyblue */\r
+ { 0x44a8dd73, 0xff6a5acd }, /* slateblue */\r
+ { 0x44ab37f8, 0xff708090 }, /* slategrey */\r
+ { 0x0035f183, 0xfffffafa }, /* snow */\r
+ { 0xd5440d16, 0xff00ff7f }, /* springgreen */\r
+ { 0x3e1524a5, 0xff4682b4 }, /* steelblue */\r
+ { 0x0001bfa1, 0xffd2b48c }, /* tan */\r
+ { 0x0036425c, 0xff008080 }, /* teal */\r
+ { 0xafc8858f, 0xffd8bfd8 }, /* thistle */\r
+ { 0xcc41600a, 0xffff6347 }, /* tomato */\r
+ { 0xfeea9b21, 0xff40e0d0 }, /* turquoise */\r
+ { 0xcf57947f, 0xffee82ee }, /* violet */\r
+ { 0x06bdbae7, 0xfff5deb3 }, /* wheat */\r
+ { 0x10802ee6, 0xfff5f5f5 }, /* whitesmoke */\r
+ { 0xe1b5130f, 0xff9acd32 }, /* yellowgreen */\r
};\r
\r
- const uint32 hash = (uint32) colourName.trim().toLowerCase().hashCode();\r
+ const auto hash = (uint32) colourName.trim().toLowerCase().hashCode();\r
\r
- for (int i = 0; i < numElementsInArray (presets); i += 2)\r
- if (presets [i] == hash)\r
- return Colour (presets [i + 1]);\r
+ for (auto entry : presets)\r
+ if (entry.stringHash == hash)\r
+ return Colour (entry.colour);\r
\r
return defaultColour;\r
}\r
\r
@tags{Graphics}\r
*/\r
-class Colours\r
+namespace Colours\r
{\r
-public:\r
- static JUCE_API const Colour\r
-\r
- //==============================================================================\r
- transparentBlack, /**< ARGB = 0x00000000 */\r
- transparentWhite, /**< ARGB = 0x00ffffff */\r
-\r
- //==============================================================================\r
- black, /**< ARGB = 0xff000000 */\r
- white, /**< ARGB = 0xffffffff */\r
- blue, /**< ARGB = 0xff0000ff */\r
- grey, /**< ARGB = 0xff808080 */\r
- green, /**< ARGB = 0xff008000 */\r
- red, /**< ARGB = 0xffff0000 */\r
- yellow, /**< ARGB = 0xffffff00 */\r
-\r
- //==============================================================================\r
- aliceblue, antiquewhite, aqua, aquamarine,\r
- azure, beige, bisque, blanchedalmond,\r
- blueviolet, brown, burlywood, cadetblue,\r
- chartreuse, chocolate, coral, cornflowerblue,\r
- cornsilk, crimson, cyan, darkblue,\r
- darkcyan, darkgoldenrod, darkgrey, darkgreen,\r
- darkkhaki, darkmagenta, darkolivegreen, darkorange,\r
- darkorchid, darkred, darksalmon, darkseagreen,\r
- darkslateblue, darkslategrey, darkturquoise, darkviolet,\r
- deeppink, deepskyblue, dimgrey, dodgerblue,\r
- firebrick, floralwhite, forestgreen, fuchsia,\r
- gainsboro, ghostwhite, gold, goldenrod,\r
- greenyellow, honeydew, hotpink, indianred,\r
- indigo, ivory, khaki, lavender,\r
- lavenderblush, lawngreen, lemonchiffon, lightblue,\r
- lightcoral, lightcyan, lightgoldenrodyellow, lightgreen,\r
- lightgrey, lightpink, lightsalmon, lightseagreen,\r
- lightskyblue, lightslategrey, lightsteelblue, lightyellow,\r
- lime, limegreen, linen, magenta,\r
- maroon, mediumaquamarine, mediumblue, mediumorchid,\r
- mediumpurple, mediumseagreen, mediumslateblue, mediumspringgreen,\r
- mediumturquoise, mediumvioletred, midnightblue, mintcream,\r
- mistyrose, moccasin, navajowhite, navy,\r
- oldlace, olive, olivedrab, orange,\r
- orangered, orchid, palegoldenrod, palegreen,\r
- paleturquoise, palevioletred, papayawhip, peachpuff,\r
- peru, pink, plum, powderblue,\r
- purple, rebeccapurple, rosybrown, royalblue,\r
- saddlebrown, salmon, sandybrown, seagreen,\r
- seashell, sienna, silver, skyblue,\r
- slateblue, slategrey, snow, springgreen,\r
- steelblue, tan, teal, thistle,\r
- tomato, turquoise, violet, wheat,\r
- whitesmoke, yellowgreen;\r
+\r
+ const Colour transparentBlack { 0 };\r
+ const Colour transparentWhite { 0x00ffffff };\r
+\r
+ const Colour aliceblue { 0xfff0f8ff };\r
+ const Colour antiquewhite { 0xfffaebd7 };\r
+ const Colour aqua { 0xff00ffff };\r
+ const Colour aquamarine { 0xff7fffd4 };\r
+ const Colour azure { 0xfff0ffff };\r
+ const Colour beige { 0xfff5f5dc };\r
+ const Colour bisque { 0xffffe4c4 };\r
+ const Colour black { 0xff000000 };\r
+ const Colour blanchedalmond { 0xffffebcd };\r
+ const Colour blue { 0xff0000ff };\r
+ const Colour blueviolet { 0xff8a2be2 };\r
+ const Colour brown { 0xffa52a2a };\r
+ const Colour burlywood { 0xffdeb887 };\r
+ const Colour cadetblue { 0xff5f9ea0 };\r
+ const Colour chartreuse { 0xff7fff00 };\r
+ const Colour chocolate { 0xffd2691e };\r
+ const Colour coral { 0xffff7f50 };\r
+ const Colour cornflowerblue { 0xff6495ed };\r
+ const Colour cornsilk { 0xfffff8dc };\r
+ const Colour crimson { 0xffdc143c };\r
+ const Colour cyan { 0xff00ffff };\r
+ const Colour darkblue { 0xff00008b };\r
+ const Colour darkcyan { 0xff008b8b };\r
+ const Colour darkgoldenrod { 0xffb8860b };\r
+ const Colour darkgrey { 0xff555555 };\r
+ const Colour darkgreen { 0xff006400 };\r
+ const Colour darkkhaki { 0xffbdb76b };\r
+ const Colour darkmagenta { 0xff8b008b };\r
+ const Colour darkolivegreen { 0xff556b2f };\r
+ const Colour darkorange { 0xffff8c00 };\r
+ const Colour darkorchid { 0xff9932cc };\r
+ const Colour darkred { 0xff8b0000 };\r
+ const Colour darksalmon { 0xffe9967a };\r
+ const Colour darkseagreen { 0xff8fbc8f };\r
+ const Colour darkslateblue { 0xff483d8b };\r
+ const Colour darkslategrey { 0xff2f4f4f };\r
+ const Colour darkturquoise { 0xff00ced1 };\r
+ const Colour darkviolet { 0xff9400d3 };\r
+ const Colour deeppink { 0xffff1493 };\r
+ const Colour deepskyblue { 0xff00bfff };\r
+ const Colour dimgrey { 0xff696969 };\r
+ const Colour dodgerblue { 0xff1e90ff };\r
+ const Colour firebrick { 0xffb22222 };\r
+ const Colour floralwhite { 0xfffffaf0 };\r
+ const Colour forestgreen { 0xff228b22 };\r
+ const Colour fuchsia { 0xffff00ff };\r
+ const Colour gainsboro { 0xffdcdcdc };\r
+ const Colour ghostwhite { 0xfff8f8ff };\r
+ const Colour gold { 0xffffd700 };\r
+ const Colour goldenrod { 0xffdaa520 };\r
+ const Colour grey { 0xff808080 };\r
+ const Colour green { 0xff008000 };\r
+ const Colour greenyellow { 0xffadff2f };\r
+ const Colour honeydew { 0xfff0fff0 };\r
+ const Colour hotpink { 0xffff69b4 };\r
+ const Colour indianred { 0xffcd5c5c };\r
+ const Colour indigo { 0xff4b0082 };\r
+ const Colour ivory { 0xfffffff0 };\r
+ const Colour khaki { 0xfff0e68c };\r
+ const Colour lavender { 0xffe6e6fa };\r
+ const Colour lavenderblush { 0xfffff0f5 };\r
+ const Colour lawngreen { 0xff7cfc00 };\r
+ const Colour lemonchiffon { 0xfffffacd };\r
+ const Colour lightblue { 0xffadd8e6 };\r
+ const Colour lightcoral { 0xfff08080 };\r
+ const Colour lightcyan { 0xffe0ffff };\r
+ const Colour lightgoldenrodyellow { 0xfffafad2 };\r
+ const Colour lightgreen { 0xff90ee90 };\r
+ const Colour lightgrey { 0xffd3d3d3 };\r
+ const Colour lightpink { 0xffffb6c1 };\r
+ const Colour lightsalmon { 0xffffa07a };\r
+ const Colour lightseagreen { 0xff20b2aa };\r
+ const Colour lightskyblue { 0xff87cefa };\r
+ const Colour lightslategrey { 0xff778899 };\r
+ const Colour lightsteelblue { 0xffb0c4de };\r
+ const Colour lightyellow { 0xffffffe0 };\r
+ const Colour lime { 0xff00ff00 };\r
+ const Colour limegreen { 0xff32cd32 };\r
+ const Colour linen { 0xfffaf0e6 };\r
+ const Colour magenta { 0xffff00ff };\r
+ const Colour maroon { 0xff800000 };\r
+ const Colour mediumaquamarine { 0xff66cdaa };\r
+ const Colour mediumblue { 0xff0000cd };\r
+ const Colour mediumorchid { 0xffba55d3 };\r
+ const Colour mediumpurple { 0xff9370db };\r
+ const Colour mediumseagreen { 0xff3cb371 };\r
+ const Colour mediumslateblue { 0xff7b68ee };\r
+ const Colour mediumspringgreen { 0xff00fa9a };\r
+ const Colour mediumturquoise { 0xff48d1cc };\r
+ const Colour mediumvioletred { 0xffc71585 };\r
+ const Colour midnightblue { 0xff191970 };\r
+ const Colour mintcream { 0xfff5fffa };\r
+ const Colour mistyrose { 0xffffe4e1 };\r
+ const Colour moccasin { 0xffffe4b5 };\r
+ const Colour navajowhite { 0xffffdead };\r
+ const Colour navy { 0xff000080 };\r
+ const Colour oldlace { 0xfffdf5e6 };\r
+ const Colour olive { 0xff808000 };\r
+ const Colour olivedrab { 0xff6b8e23 };\r
+ const Colour orange { 0xffffa500 };\r
+ const Colour orangered { 0xffff4500 };\r
+ const Colour orchid { 0xffda70d6 };\r
+ const Colour palegoldenrod { 0xffeee8aa };\r
+ const Colour palegreen { 0xff98fb98 };\r
+ const Colour paleturquoise { 0xffafeeee };\r
+ const Colour palevioletred { 0xffdb7093 };\r
+ const Colour papayawhip { 0xffffefd5 };\r
+ const Colour peachpuff { 0xffffdab9 };\r
+ const Colour peru { 0xffcd853f };\r
+ const Colour pink { 0xffffc0cb };\r
+ const Colour plum { 0xffdda0dd };\r
+ const Colour powderblue { 0xffb0e0e6 };\r
+ const Colour purple { 0xff800080 };\r
+ const Colour rebeccapurple { 0xff663399 };\r
+ const Colour red { 0xffff0000 };\r
+ const Colour rosybrown { 0xffbc8f8f };\r
+ const Colour royalblue { 0xff4169e1 };\r
+ const Colour saddlebrown { 0xff8b4513 };\r
+ const Colour salmon { 0xfffa8072 };\r
+ const Colour sandybrown { 0xfff4a460 };\r
+ const Colour seagreen { 0xff2e8b57 };\r
+ const Colour seashell { 0xfffff5ee };\r
+ const Colour sienna { 0xffa0522d };\r
+ const Colour silver { 0xffc0c0c0 };\r
+ const Colour skyblue { 0xff87ceeb };\r
+ const Colour slateblue { 0xff6a5acd };\r
+ const Colour slategrey { 0xff708090 };\r
+ const Colour snow { 0xfffffafa };\r
+ const Colour springgreen { 0xff00ff7f };\r
+ const Colour steelblue { 0xff4682b4 };\r
+ const Colour tan { 0xffd2b48c };\r
+ const Colour teal { 0xff008080 };\r
+ const Colour thistle { 0xffd8bfd8 };\r
+ const Colour tomato { 0xffff6347 };\r
+ const Colour turquoise { 0xff40e0d0 };\r
+ const Colour violet { 0xffee82ee };\r
+ const Colour wheat { 0xfff5deb3 };\r
+ const Colour white { 0xffffffff };\r
+ const Colour whitesmoke { 0xfff5f5f5 };\r
+ const Colour yellow { 0xffffff00 };\r
+ const Colour yellowgreen { 0xff9acd32 };\r
\r
/** Attempts to look up a string in the list of known colour names, and return\r
the appropriate colour.\r
if a match is found, that colour is returned. If no match is found, the\r
colour passed in as the defaultColour parameter is returned.\r
*/\r
- static JUCE_API Colour findColourForName (const String& colourName,\r
- Colour defaultColour);\r
-\r
-private:\r
- //==============================================================================\r
- // this isn't a class you should ever instantiate - it's just here for the\r
- // static values in it.\r
- Colours();\r
-\r
- JUCE_DECLARE_NON_COPYABLE (Colours)\r
-};\r
+ JUCE_API Colour findColourForName (const String& colourName,\r
+ Colour defaultColour);\r
+} // namespace Colours\r
\r
} // namespace juce\r
/** Draws part of an image, rescaling it to fit in a given target region.\r
\r
The specified area of the source image is rescaled and drawn to fill the\r
- specifed destination rectangle.\r
+ specified destination rectangle.\r
\r
Images are composited using the context's current opacity, so if you\r
don't want it to be drawn semi-transparently, be sure to call setOpacity (1.0f)\r
\r
This may also be set to Font::getDefaultSansSerifFontName(), Font::getDefaultSerifFontName(),\r
or Font::getDefaultMonospacedFontName(), which are not actual platform-specific font family names,\r
- but are generic font familiy names that are used to represent the various default fonts.\r
+ but are generic font family names that are used to represent the various default fonts.\r
\r
If you need to know the exact typeface font family being used, you can call\r
Font::getTypeface()->getName(), which will give you the platform-specific font family.\r
\r
for (int i = 0; i < glyphs.size(); ++i)\r
{\r
- auto& pg = glyphs.getReference(i);\r
+ auto& pg = glyphs.getReference (i);\r
\r
if (pg.font.isUnderlined())\r
drawGlyphUnderline (g, pg, i, transform);\r
auto origin = justification.appliedToRectangle (Rectangle<float> (width, getHeight()), area).getPosition();\r
\r
auto& context = g.getInternalContext();\r
+ context.saveState();\r
+\r
auto clip = context.getClipBounds();\r
auto clipTop = clip.getY() - origin.y;\r
auto clipBottom = clip.getBottom() - origin.y;\r
}\r
}\r
}\r
+\r
+ context.restoreState();\r
}\r
\r
void TextLayout::createLayout (const AttributedString& text, float maxWidth)\r
*/\r
virtual bool getOutlineForGlyph (int glyphNumber, Path& path) = 0;\r
\r
- /** Returns a new EdgeTable that contains the path for the givem glyph, with the specified transform applied. */\r
+ /** Returns a new EdgeTable that contains the path for the given glyph, with the specified transform applied. */\r
virtual EdgeTable* getEdgeTableForGlyph (int glyphNumber, const AffineTransform& transform, float fontHeight);\r
\r
/** Returns true if the typeface uses hinting. */\r
*/\r
float getScaleFactor() const noexcept;\r
\r
- /* A ready-to-use identity transform - now depracated.\r
+ /* A ready-to-use identity transform - now deprecated.\r
@deprecated If you need an identity transform, just use AffineTransform() or {}.\r
*/\r
JUCE_DEPRECATED_STATIC (static const AffineTransform identity;)\r
+ (bottomLeft - topLeft) * relativePosition.y;\r
}\r
\r
- /** Returns a transformed verstion of the parallelogram. */\r
+ /** Returns a transformed version of the parallelogram. */\r
Parallelogram transformedBy (const AffineTransform& transform) const noexcept\r
{\r
auto p = *this;\r
draw a curve clockwise from the 9 o'clock position to the 3 o'clock position via\r
12 o'clock, you'd use 1.5*Pi and 2.5*Pi as the start and finish points.\r
@param startAsNewSubPath if true, the arc will begin a new subpath from its starting point; if false,\r
- it will be added to the current sub-path, continuing from the current postition\r
+ it will be added to the current sub-path, continuing from the current position\r
\r
@see addCentredArc, arcTo, addPieSegment, addEllipse\r
*/\r
draw a curve clockwise from the 9 o'clock position to the 3 o'clock position via\r
12 o'clock, you'd use 1.5*Pi and 2.5*Pi as the start and finish points.\r
@param startAsNewSubPath if true, the arc will begin a new subpath from its starting point; if false,\r
- it will be added to the current sub-path, continuing from the current postition\r
+ it will be added to the current sub-path, continuing from the current position\r
\r
@see addArc, arcTo\r
*/\r
@param preserveProportions if true, it will fit the path into the space without altering its\r
horizontal/vertical scale ratio; if false, it will distort the\r
path to fill the specified ratio both horizontally and vertically\r
- @param justificationType if the proportions are preseved, the resultant path may be smaller\r
+ @param justificationType if the proportions are preserved, the resultant path may be smaller\r
than the available rectangle, so this describes how it should be\r
positioned within the space.\r
@returns an appropriate transformation\r
@param preserveProportions if true, it will fit the path into the space without altering its\r
horizontal/vertical scale ratio; if false, it will distort the\r
path to fill the specified ratio both horizontally and vertically\r
- @param justificationType if the proportions are preseved, the resultant path may be smaller\r
+ @param justificationType if the proportions are preserved, the resultant path may be smaller\r
than the available rectangle, so this describes how it should be\r
positioned within the space.\r
@returns an appropriate transformation\r
\r
/** Returns the colour of a given pixel.\r
For performance reasons, this won't do any bounds-checking on the coordinates, so it's the caller's\r
- repsonsibility to make sure they're within the image's size.\r
+ responsibility to make sure they're within the image's size.\r
*/\r
Colour getPixelColour (int x, int y) const noexcept;\r
\r
/** Sets the colour of a given pixel.\r
For performance reasons, this won't do any bounds-checking on the coordinates, so it's the caller's\r
- repsonsibility to make sure they're within the image's size.\r
+ responsibility to make sure they're within the image's size.\r
*/\r
void setPixelColour (int x, int y, Colour colour) const noexcept;\r
\r
{\r
public:\r
//==============================================================================\r
- /** Creates an empty convulution kernel.\r
+ /** Creates an empty convolution kernel.\r
\r
@param size the length of each dimension of the kernel, so e.g. if the size\r
is 5, it will create a 5x5 kernel\r
/** Multiplies all values in the kernel by a value. */\r
void rescaleAllValues (float multiplier);\r
\r
- /** Intialises the kernel for a gaussian blur.\r
+ /** Initialises the kernel for a gaussian blur.\r
\r
@param blurRadius this may be larger or smaller than the kernel's actual\r
size but this will obviously be wasteful or clip at the\r
==============================================================================\r
*/\r
\r
+\r
/*******************************************************************************\r
The block below describes the properties of this module, and is read by\r
the Projucer to automatically generate project code that uses it.\r
\r
BEGIN_JUCE_MODULE_DECLARATION\r
\r
- ID: juce_graphics\r
- vendor: juce\r
- version: 5.4.5\r
- name: JUCE graphics classes\r
- description: Classes for 2D vector graphics, image loading/saving, font handling, etc.\r
- website: http://www.juce.com/juce\r
- license: GPL/Commercial\r
-\r
- dependencies: juce_events\r
- OSXFrameworks: Cocoa QuartzCore\r
- iOSFrameworks: CoreGraphics CoreImage CoreText QuartzCore\r
- linuxPackages: x11 xinerama xext freetype2\r
+ ID: juce_graphics\r
+ vendor: juce\r
+ version: 5.4.6\r
+ name: JUCE graphics classes\r
+ description: Classes for 2D vector graphics, image loading/saving, font handling, etc.\r
+ website: http://www.juce.com/juce\r
+ license: GPL/Commercial\r
+\r
+ dependencies: juce_events\r
+ OSXFrameworks: Cocoa QuartzCore\r
+ iOSFrameworks: CoreGraphics CoreImage CoreText QuartzCore\r
+ linuxPackages: x11 xinerama xext freetype2\r
\r
END_JUCE_MODULE_DECLARATION\r
\r
FillType fillType;\r
Font font;\r
CGFontRef fontRef = {};\r
- AffineTransform fontTransform, inverseFontTransform;\r
+ CGAffineTransform textMatrix = CGAffineTransformIdentity,\r
+ inverseTextMatrix = CGAffineTransformIdentity;\r
CGGradientRef gradient = {};\r
};\r
\r
{\r
\r
//==============================================================================\r
-class CoreGraphicsImage : public ImagePixelData\r
+// This class has been renamed from CoreGraphicsImage to avoid a symbol\r
+// collision in Pro Tools 2019.12 and possibly 2020 depending on the Pro Tools\r
+// release schedule.\r
+class CoreGraphicsPixelData : public ImagePixelData\r
{\r
public:\r
- CoreGraphicsImage (const Image::PixelFormat format, int w, int h, bool clearImage)\r
+ CoreGraphicsPixelData (const Image::PixelFormat format, int w, int h, bool clearImage)\r
: ImagePixelData (format, w, h)\r
{\r
pixelStride = format == Image::RGB ? 3 : ((format == Image::ARGB) ? 4 : 1);\r
CGColorSpaceRelease (colourSpace);\r
}\r
\r
- ~CoreGraphicsImage() override\r
+ ~CoreGraphicsPixelData() override\r
{\r
freeCachedImageRef();\r
CGContextRelease (context);\r
\r
ImagePixelData::Ptr clone() override\r
{\r
- auto im = new CoreGraphicsImage (pixelFormat, width, height, false);\r
+ auto im = new CoreGraphicsPixelData (pixelFormat, width, height, false);\r
memcpy (im->imageDataHolder->data, imageDataHolder->data, (size_t) (lineStride * height));\r
return *im;\r
}\r
//==============================================================================\r
static CGImageRef getCachedImageRef (const Image& juceImage, CGColorSpaceRef colourSpace)\r
{\r
- auto cgim = dynamic_cast<CoreGraphicsImage*> (juceImage.getPixelData());\r
+ auto cgim = dynamic_cast<CoreGraphicsPixelData*> (juceImage.getPixelData());\r
\r
if (cgim != nullptr && cgim->cachedImageRef != nullptr)\r
{\r
{\r
auto* imageDataContainer = [](const Image& img) -> HeapBlockContainer::Ptr*\r
{\r
- if (auto* cgim = dynamic_cast<CoreGraphicsImage*> (img.getPixelData()))\r
+ if (auto* cgim = dynamic_cast<CoreGraphicsPixelData*> (img.getPixelData()))\r
return new HeapBlockContainer::Ptr (cgim->imageDataHolder);\r
\r
return nullptr;\r
#endif\r
}\r
\r
- JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CoreGraphicsImage)\r
+ JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CoreGraphicsPixelData)\r
};\r
\r
ImagePixelData::Ptr NativeImageType::create (Image::PixelFormat format, int width, int height, bool clearImage) const\r
{\r
- return *new CoreGraphicsImage (format == Image::RGB ? Image::ARGB : format, width, height, clearImage);\r
+ return *new CoreGraphicsPixelData (format == Image::RGB ? Image::ARGB : format, width, height, clearImage);\r
}\r
\r
//==============================================================================\r
if (sourceImage.getFormat() != Image::SingleChannel)\r
singleChannelImage = sourceImage.convertedToFormat (Image::SingleChannel);\r
\r
- CGImageRef image = CoreGraphicsImage::createImage (singleChannelImage, greyColourSpace, true);\r
+ CGImageRef image = CoreGraphicsPixelData::createImage (singleChannelImage, greyColourSpace, true);\r
\r
flip();\r
auto t = AffineTransform::verticalFlip (sourceImage.getHeight()).followedBy (transform);\r
if (auto* top = stateStack.getLast())\r
{\r
state.reset (top);\r
+ CGContextSetTextMatrix (context, state->textMatrix);\r
+\r
stateStack.removeLast (1, false);\r
lastClipRectIsValid = false;\r
}\r
\r
auto colourSpace = sourceImage.getFormat() == Image::PixelFormat::SingleChannel ? greyColourSpace\r
: rgbColourSpace;\r
- CGImageRef image = CoreGraphicsImage::getCachedImageRef (sourceImage, colourSpace);\r
+ CGImageRef image = CoreGraphicsPixelData::getCachedImageRef (sourceImage, colourSpace);\r
\r
CGContextSaveGState (context);\r
CGContextSetAlpha (context, state->fillType.getOpacity());\r
CGContextSetFont (context, state->fontRef);\r
CGContextSetFontSize (context, state->font.getHeight() * osxTypeface->fontHeightToPointsFactor);\r
\r
- auto fontTransform = osxTypeface->renderingTransform;\r
- fontTransform.a *= state->font.getHorizontalScale();\r
- CGContextSetTextMatrix (context, fontTransform);\r
-\r
- auto cgTransformToJuceTransform = [](CGAffineTransform& t) -> AffineTransform\r
- {\r
- return { (float) t.a, (float) t.c, (float) t.tx,\r
- (float) t.b, (float) t.d, (float) t.ty };\r
- };\r
-\r
- state->fontTransform = cgTransformToJuceTransform (fontTransform);\r
- auto inverseFontTransform = CGAffineTransformInvert (fontTransform);\r
- state->inverseFontTransform = cgTransformToJuceTransform (inverseFontTransform);\r
- }\r
+ state->textMatrix = osxTypeface->renderingTransform;\r
+ state->textMatrix.a *= state->font.getHorizontalScale();\r
+ CGContextSetTextMatrix (context, state->textMatrix);\r
+ state->inverseTextMatrix = CGAffineTransformInvert (state->textMatrix);\r
+ }\r
}\r
}\r
\r
{\r
if (state->fontRef != nullptr && state->fillType.isColour())\r
{\r
- if (transform.isOnlyTranslation() && state->fontTransform.isOnlyTranslation())\r
+ auto cgTransformIsOnlyTranslation = [](CGAffineTransform t)\r
+ {\r
+ return t.a == 1.0f && t.d == 1.0f && t.b == 0.0f && t.c == 0.0f;\r
+ };\r
+\r
+ if (transform.isOnlyTranslation() && cgTransformIsOnlyTranslation (state->inverseTextMatrix))\r
{\r
- auto t = transform.followedBy (state->inverseFontTransform);\r
+ auto x = transform.mat02 + state->inverseTextMatrix.tx;\r
+ auto y = transform.mat12 + state->inverseTextMatrix.ty;\r
\r
CGGlyph glyphs[1] = { (CGGlyph) glyphNumber };\r
- CGPoint positions[1] = { { t.getTranslationX(), flipHeight - roundToInt (t.getTranslationY()) } };\r
+ CGPoint positions[1] = { { x, flipHeight - roundToInt (y) } };\r
CGContextShowGlyphsAtPositions (context, glyphs, positions, 1);\r
}\r
else\r
CGContextSaveGState (context);\r
\r
flip();\r
- auto fontTransform = state->fontTransform;\r
- fontTransform.mat11 = -fontTransform.mat11;\r
- applyTransform (fontTransform.followedBy (state->inverseFontTransform).followedBy (transform));\r
+ applyTransform (transform);\r
+ CGContextConcatCTM (context, state->inverseTextMatrix);\r
+ auto cgTransform = state->textMatrix;\r
+ cgTransform.d = -cgTransform.d;\r
+ CGContextConcatCTM (context, cgTransform);\r
\r
CGGlyph glyphs[1] = { (CGGlyph) glyphNumber };\r
CGPoint positions[1] = { { 0.0f, 0.0f } };\r
\r
CoreGraphicsContext::SavedState::SavedState (const SavedState& other)\r
: fillType (other.fillType), font (other.font), fontRef (other.fontRef),\r
- fontTransform (other.fontTransform),\r
- inverseFontTransform (other.inverseFontTransform),\r
+ textMatrix (other.textMatrix), inverseTextMatrix (other.inverseTextMatrix),\r
gradient (other.gradient)\r
{\r
if (gradient != nullptr)\r
(int) CGImageGetHeight (loadedImage),\r
hasAlphaChan));\r
\r
- auto cgImage = dynamic_cast<CoreGraphicsImage*> (image.getPixelData());\r
- jassert (cgImage != nullptr); // if USE_COREGRAPHICS_RENDERING is set, the CoreGraphicsImage class should have been used.\r
+ auto cgImage = dynamic_cast<CoreGraphicsPixelData*> (image.getPixelData());\r
+ jassert (cgImage != nullptr); // if USE_COREGRAPHICS_RENDERING is set, the CoreGraphicsPixelData class should have been used.\r
\r
CGContextDrawImage (cgImage->context, convertToCGRect (image.getBounds()), loadedImage);\r
CGContextFlush (cgImage->context);\r
Image juce_createImageFromCIImage (CIImage*, int, int);\r
Image juce_createImageFromCIImage (CIImage* im, int w, int h)\r
{\r
- auto cgImage = new CoreGraphicsImage (Image::ARGB, w, h, false);\r
+ auto cgImage = new CoreGraphicsPixelData (Image::ARGB, w, h, false);\r
\r
CIContext* cic = [CIContext contextWithCGContext: cgImage->context options: nil];\r
[cic drawImage: im inRect: CGRectMake (0, 0, w, h) fromRect: CGRectMake (0, 0, w, h)];\r
CGImageRef juce_createCoreGraphicsImage (const Image& juceImage, CGColorSpaceRef colourSpace,\r
const bool mustOutliveSource)\r
{\r
- return CoreGraphicsImage::createImage (juceImage, colourSpace, mustOutliveSource);\r
+ return CoreGraphicsPixelData::createImage (juceImage, colourSpace, mustOutliveSource);\r
}\r
\r
CGContextRef juce_getImageContext (const Image& image)\r
{\r
- if (auto cgi = dynamic_cast<CoreGraphicsImage*> (image.getPixelData()))\r
+ if (auto cgi = dynamic_cast<CoreGraphicsPixelData*> (image.getPixelData()))\r
return cgi->context;\r
\r
jassertfalse;\r
\r
CTParagraphStyleSetting settings[] =\r
{\r
- { kCTParagraphStyleSpecifierAlignment, sizeof (CTTextAlignment), &ctTextAlignment },\r
- { kCTParagraphStyleSpecifierLineBreakMode, sizeof (CTLineBreakMode), &ctLineBreakMode },\r
+ { kCTParagraphStyleSpecifierAlignment, sizeof (CTTextAlignment), &ctTextAlignment },\r
+ { kCTParagraphStyleSpecifierLineBreakMode, sizeof (CTLineBreakMode), &ctLineBreakMode },\r
{ kCTParagraphStyleSpecifierBaseWritingDirection, sizeof (CTWritingDirection), &ctWritingDirection},\r
- { kCTParagraphStyleSpecifierLineSpacingAdjustment, sizeof (CGFloat), &ctLineSpacing }\r
+ { kCTParagraphStyleSpecifierLineSpacingAdjustment, sizeof (CGFloat), &ctLineSpacing }\r
};\r
\r
auto ctParagraphStyleRef = CTParagraphStyleCreate (settings, (size_t) numElementsInArray (settings));\r
return attribString;\r
}\r
\r
- static CTFrameRef createCTFrame (const AttributedString& text, CGRect bounds)\r
+ static CTFramesetterRef createCTFramesetter (const AttributedString& text)\r
{\r
auto attribString = createCFAttributedString (text);\r
auto framesetter = CTFramesetterCreateWithAttributedString (attribString);\r
CFRelease (attribString);\r
\r
+ return framesetter;\r
+ }\r
+\r
+ static CTFrameRef createCTFrame (CTFramesetterRef framesetter, CGRect bounds)\r
+ {\r
auto path = CGPathCreateMutable();\r
CGPathAddRect (path, nullptr, bounds);\r
\r
auto frame = CTFramesetterCreateFrame (framesetter, CFRangeMake (0, 0), path, nullptr);\r
- CFRelease (framesetter);\r
CGPathRelease (path);\r
\r
return frame;\r
}\r
\r
+ static CTFrameRef createCTFrame (const AttributedString& text, CGRect bounds)\r
+ {\r
+ auto framesetter = createCTFramesetter (text);\r
+ auto frame = createCTFrame (framesetter, bounds);\r
+ CFRelease (framesetter);\r
+\r
+ return frame;\r
+ }\r
+\r
static Range<float> getLineVerticalRange (CTFrameRef frame, CFArrayRef lines, int lineIndex)\r
{\r
LineInfo info (frame, (CTLineRef) CFArrayGetValueAtIndex (lines, lineIndex), lineIndex);\r
static void drawToCGContext (const AttributedString& text, const Rectangle<float>& area,\r
const CGContextRef& context, float flipHeight)\r
{\r
- Rectangle<float> ctFrameArea;\r
- auto verticalJustification = text.getJustification().getOnlyVerticalFlags();\r
+ auto framesetter = createCTFramesetter (text);\r
\r
// Ugly hack to fix a bug in OS X Sierra where the CTFrame needs to be slightly\r
// larger than the font height - otherwise the CTFrame will be invalid\r
- if (verticalJustification == Justification::verticallyCentred)\r
- ctFrameArea = area.withSizeKeepingCentre (area.getWidth(), area.getHeight() * 1.1f);\r
- else if (verticalJustification == Justification::bottom)\r
- ctFrameArea = area.withTop (area.getY() - (area.getHeight() * 0.1f));\r
- else\r
- ctFrameArea = area.withHeight (area.getHeight() * 1.1f);\r
\r
- auto frame = createCTFrame (text, CGRectMake ((CGFloat) ctFrameArea.getX(), flipHeight - (CGFloat) ctFrameArea.getBottom(),\r
- (CGFloat) ctFrameArea.getWidth(), (CGFloat) ctFrameArea.getHeight()));\r
+ CFRange fitrange;\r
+ auto suggestedSingleLineFrameSize =\r
+ CTFramesetterSuggestFrameSizeWithConstraints (framesetter, CFRangeMake (0, 0), nullptr,\r
+ CGSizeMake (CGFLOAT_MAX, CGFLOAT_MAX), &fitrange);\r
+ auto minCTFrameHeight = (float) suggestedSingleLineFrameSize.height;\r
+\r
+ auto verticalJustification = text.getJustification().getOnlyVerticalFlags();\r
+\r
+ auto ctFrameArea = [area, minCTFrameHeight, verticalJustification]\r
+ {\r
+ if (minCTFrameHeight < area.getHeight())\r
+ return area;\r
+\r
+ if (verticalJustification == Justification::verticallyCentred)\r
+ return area.withSizeKeepingCentre (area.getWidth(), minCTFrameHeight);\r
+\r
+ auto frameArea = area.withHeight (minCTFrameHeight);\r
+\r
+ if (verticalJustification == Justification::bottom)\r
+ return frameArea.withBottomY (area.getBottom());\r
+\r
+ return frameArea;\r
+ }();\r
+\r
+ auto frame = createCTFrame (framesetter, CGRectMake ((CGFloat) ctFrameArea.getX(), flipHeight - (CGFloat) ctFrameArea.getBottom(),\r
+ (CGFloat) ctFrameArea.getWidth(), (CGFloat) ctFrameArea.getHeight()));\r
+ CFRelease (framesetter);\r
+\r
+ auto textMatrix = CGContextGetTextMatrix (context);\r
+ CGContextSaveGState (context);\r
\r
if (verticalJustification == Justification::verticallyCentred\r
- || verticalJustification == Justification::bottom)\r
+ || verticalJustification == Justification::bottom)\r
{\r
auto adjust = ctFrameArea.getHeight() - findCTFrameHeight (frame);\r
\r
if (verticalJustification == Justification::verticallyCentred)\r
adjust *= 0.5f;\r
\r
- CGContextSaveGState (context);\r
CGContextTranslateCTM (context, 0, -adjust);\r
- CTFrameDraw (frame, context);\r
- CGContextRestoreGState (context);\r
- }\r
- else\r
- {\r
- CTFrameDraw (frame, context);\r
}\r
\r
+ CTFrameDraw (frame, context);\r
+\r
+ CGContextRestoreGState (context);\r
+ CGContextSetTextMatrix (context, textMatrix);\r
+\r
CFRelease (frame);\r
}\r
\r
template <typename Type>\r
D2D1_RECT_F rectangleToRectF (const Rectangle<Type>& r)\r
{\r
- return D2D1::RectF ((float) r.getX(), (float) r.getY(), (float) r.getRight(), (float) r.getBottom());\r
+ return { (float) r.getX(), (float) r.getY(), (float) r.getRight(), (float) r.getBottom() };\r
}\r
\r
static D2D1_COLOR_F colourToD2D (Colour c)\r
{\r
- return D2D1::ColorF::ColorF (c.getFloatRed(), c.getFloatGreen(), c.getFloatBlue(), c.getFloatAlpha());\r
+ return { c.getFloatRed(), c.getFloatGreen(), c.getFloatBlue(), c.getFloatAlpha() };\r
}\r
\r
static void pathToGeometrySink (const Path& path, ID2D1GeometrySink* sink, const AffineTransform& transform)\r
{\r
case Path::Iterator::cubicTo:\r
{\r
- D2D1_BEZIER_SEGMENT seg;\r
+ transform.transformPoint (it.x1, it.y1);\r
+ transform.transformPoint (it.x2, it.y2);\r
+ transform.transformPoint (it.x3, it.y3);\r
\r
- transform.transformPoint (it.x1, it.y1);\r
- seg.point1 = D2D1::Point2F (it.x1, it.y1);\r
-\r
- transform.transformPoint (it.x2, it.y2);\r
- seg.point2 = D2D1::Point2F (it.x2, it.y2);\r
-\r
- transform.transformPoint (it.x3, it.y3);\r
- seg.point3 = D2D1::Point2F (it.x3, it.y3);\r
-\r
- sink->AddBezier (seg);\r
+ sink->AddBezier ({ { it.x1, it.y1 }, { it.x2, it.y2 }, { it.x3, it.y3 } });\r
break;\r
}\r
\r
case Path::Iterator::lineTo:\r
{\r
- transform.transformPoint (it.x1, it.y1);\r
- sink->AddLine (D2D1::Point2F (it.x1, it.y1));\r
+ transform.transformPoint (it.x1, it.y1);\r
+ sink->AddLine ({ it.x1, it.y1 });\r
break;\r
}\r
\r
case Path::Iterator::quadraticTo:\r
{\r
- D2D1_QUADRATIC_BEZIER_SEGMENT seg;\r
-\r
- transform.transformPoint (it.x1, it.y1);\r
- seg.point1 = D2D1::Point2F (it.x1, it.y1);\r
-\r
- transform.transformPoint (it.x2, it.y2);\r
- seg.point2 = D2D1::Point2F (it.x2, it.y2);\r
-\r
- sink->AddQuadraticBezier (seg);\r
+ transform.transformPoint (it.x1, it.y1);\r
+ transform.transformPoint (it.x2, it.y2);\r
+ sink->AddQuadraticBezier ({ { it.x1, it.y1 }, { it.x2, it.y2 } });\r
break;\r
}\r
\r
\r
case Path::Iterator::startNewSubPath:\r
{\r
- transform.transformPoint (it.x1, it.y1);\r
- sink->BeginFigure (D2D1::Point2F (it.x1, it.y1), D2D1_FIGURE_BEGIN_FILLED);\r
+ transform.transformPoint (it.x1, it.y1);\r
+ sink->BeginFigure ({ it.x1, it.y1 }, D2D1_FIGURE_BEGIN_FILLED);\r
break;\r
}\r
}\r
\r
static D2D1::Matrix3x2F transformToMatrix (const AffineTransform& transform)\r
{\r
- D2D1::Matrix3x2F matrix;\r
- matrix._11 = transform.mat00;\r
- matrix._12 = transform.mat10;\r
- matrix._21 = transform.mat01;\r
- matrix._22 = transform.mat11;\r
- matrix._31 = transform.mat02;\r
- matrix._32 = transform.mat12;\r
- return matrix;\r
+ return { transform.mat00, transform.mat10, transform.mat01, transform.mat11, transform.mat02, transform.mat12 };\r
}\r
\r
static D2D1_POINT_2F pointTransformed (int x, int y, const AffineTransform& transform)\r
{\r
transform.transformPoint (x, y);\r
- return D2D1::Point2F ((FLOAT) x, (FLOAT) y);\r
+ return { (FLOAT) x, (FLOAT) y };\r
}\r
\r
static void rectToGeometrySink (const Rectangle<int>& rect, ID2D1GeometrySink* sink, const AffineTransform& transform)\r
factories->d2dFactory->CreatePathGeometry (&p);\r
\r
ComSmartPtr<ID2D1GeometrySink> sink;\r
- HRESULT hr = p->Open (sink.resetAndGetPointerAddress()); // xxx handle error\r
+ auto hr = p->Open (sink.resetAndGetPointerAddress()); // xxx handle error\r
sink->SetFillMode (D2D1_FILL_MODE_WINDING);\r
\r
for (int i = clipRegion.getNumRectangles(); --i >= 0;)\r
factories->d2dFactory->CreatePathGeometry (&p);\r
\r
ComSmartPtr<ID2D1GeometrySink> sink;\r
- HRESULT hr = p->Open (sink.resetAndGetPointerAddress());\r
+ auto hr = p->Open (sink.resetAndGetPointerAddress());\r
sink->SetFillMode (D2D1_FILL_MODE_WINDING); // xxx need to check Path::isUsingNonZeroWinding()\r
\r
pathToGeometrySink (path, sink, transform);\r
}\r
else\r
{\r
- const D2D1_SIZE_U size (owner.pimpl->renderingTarget->GetPixelSize());\r
+ const auto size = owner.pimpl->renderingTarget->GetPixelSize();\r
clipRect.setSize (size.width, size.height);\r
setFill (FillType (Colours::black));\r
}\r
void clipToRectangle (const Rectangle<int>& r)\r
{\r
clearClip();\r
- clipRect = r.toFloat().transformed (transform).getSmallestIntegerContainer();\r
+ clipRect = r.toFloat().transformedBy (transform).getSmallestIntegerContainer();\r
shouldClipRect = true;\r
pushClips();\r
}\r
if (bitmapMaskLayer == nullptr)\r
owner.pimpl->renderingTarget->CreateLayer (bitmapMaskLayer.resetAndGetPointerAddress());\r
\r
- D2D1_BRUSH_PROPERTIES brushProps;\r
- brushProps.opacity = 1;\r
- brushProps.transform = transformToMatrix (clipTransform);\r
-\r
- D2D1_BITMAP_BRUSH_PROPERTIES bmProps = D2D1::BitmapBrushProperties (D2D1_EXTEND_MODE_WRAP, D2D1_EXTEND_MODE_WRAP);\r
-\r
- D2D1_SIZE_U size;\r
- size.width = clipImage.getWidth();\r
- size.height = clipImage.getHeight();\r
-\r
- D2D1_BITMAP_PROPERTIES bp = D2D1::BitmapProperties();\r
+ D2D1_BRUSH_PROPERTIES brushProps = { 1, transformToMatrix (clipTransform) };\r
+ auto bmProps = D2D1::BitmapBrushProperties (D2D1_EXTEND_MODE_WRAP, D2D1_EXTEND_MODE_WRAP);\r
+ D2D1_SIZE_U size = { (UINT32) clipImage.getWidth(), (UINT32) clipImage.getHeight() };\r
+ auto bp = D2D1::BitmapProperties();\r
\r
maskImage = clipImage.convertedToFormat (Image::ARGB);\r
Image::BitmapData bd (maskImage, Image::BitmapData::readOnly); // xxx should be maskImage?\r
bp.pixelFormat = owner.pimpl->renderingTarget->GetPixelFormat();\r
bp.pixelFormat.alphaMode = D2D1_ALPHA_MODE_PREMULTIPLIED;\r
\r
- HRESULT hr = owner.pimpl->renderingTarget->CreateBitmap (size, bd.data, bd.lineStride, bp, maskBitmap.resetAndGetPointerAddress());\r
+ auto hr = owner.pimpl->renderingTarget->CreateBitmap (size, bd.data, bd.lineStride, bp, maskBitmap.resetAndGetPointerAddress());\r
hr = owner.pimpl->renderingTarget->CreateBitmapBrush (maskBitmap, bmProps, brushProps, bitmapMaskBrush.resetAndGetPointerAddress());\r
\r
imageMaskLayerParams = D2D1::LayerParameters();\r
\r
if (shouldClipRectList && !clipsRectList)\r
{\r
- D2D1_LAYER_PARAMETERS layerParams = D2D1::LayerParameters();\r
+ auto layerParams = D2D1::LayerParameters();\r
rectListGeometry->GetBounds (D2D1::IdentityMatrix(), &layerParams.contentBounds);\r
layerParams.geometricMask = rectListGeometry;\r
owner.pimpl->renderingTarget->PushLayer (layerParams, rectListLayer);\r
\r
if (shouldClipComplex && !clipsComplex)\r
{\r
- D2D1_LAYER_PARAMETERS layerParams = D2D1::LayerParameters();\r
+ auto layerParams = D2D1::LayerParameters();\r
complexClipGeometry->GetBounds (D2D1::IdentityMatrix(), &layerParams.contentBounds);\r
layerParams.geometricMask = complexClipGeometry;\r
owner.pimpl->renderingTarget->PushLayer (layerParams, complexClipLayer);\r
{\r
if (currentFontFace == nullptr)\r
{\r
- WindowsDirectWriteTypeface* typeface = dynamic_cast<WindowsDirectWriteTypeface*> (font.getTypeface());\r
+ auto* typeface = dynamic_cast<WindowsDirectWriteTypeface*> (font.getTypeface());\r
currentFontFace = typeface->getIDWriteFontFace();\r
fontHeightToEmSizeFactor = typeface->getUnitsToHeightScaleFactor();\r
}\r
{\r
if (fillType.isColour())\r
{\r
- D2D1_COLOR_F colour = colourToD2D (fillType.colour);\r
+ auto colour = colourToD2D (fillType.colour);\r
owner.pimpl->colourBrush->SetColor (colour);\r
currentBrush = owner.pimpl->colourBrush;\r
}\r
else if (fillType.isTiledImage())\r
{\r
- D2D1_BRUSH_PROPERTIES brushProps;\r
- brushProps.opacity = fillType.getOpacity();\r
- brushProps.transform = transformToMatrix (fillType.transform);\r
-\r
- D2D1_BITMAP_BRUSH_PROPERTIES bmProps = D2D1::BitmapBrushProperties (D2D1_EXTEND_MODE_WRAP, D2D1_EXTEND_MODE_WRAP);\r
+ D2D1_BRUSH_PROPERTIES brushProps = { fillType.getOpacity(), transformToMatrix (fillType.transform) };\r
+ auto bmProps = D2D1::BitmapBrushProperties (D2D1_EXTEND_MODE_WRAP, D2D1_EXTEND_MODE_WRAP);\r
\r
image = fillType.image;\r
\r
- D2D1_SIZE_U size;\r
- size.width = image.getWidth();\r
- size.height = image.getHeight();\r
-\r
- D2D1_BITMAP_PROPERTIES bp = D2D1::BitmapProperties();\r
+ D2D1_SIZE_U size = { (UINT32) image.getWidth(), (UINT32) image.getHeight() };\r
+ auto bp = D2D1::BitmapProperties();\r
\r
this->image = image.convertedToFormat (Image::ARGB);\r
Image::BitmapData bd (this->image, Image::BitmapData::readOnly);\r
bp.pixelFormat = owner.pimpl->renderingTarget->GetPixelFormat();\r
bp.pixelFormat.alphaMode = D2D1_ALPHA_MODE_PREMULTIPLIED;\r
\r
- HRESULT hr = owner.pimpl->renderingTarget->CreateBitmap (size, bd.data, bd.lineStride, bp, bitmap.resetAndGetPointerAddress());\r
+ auto hr = owner.pimpl->renderingTarget->CreateBitmap (size, bd.data, bd.lineStride, bp, bitmap.resetAndGetPointerAddress());\r
hr = owner.pimpl->renderingTarget->CreateBitmapBrush (bitmap, bmProps, brushProps, bitmapBrush.resetAndGetPointerAddress());\r
\r
currentBrush = bitmapBrush;\r
{\r
gradientStops = nullptr;\r
\r
- D2D1_BRUSH_PROPERTIES brushProps;\r
- brushProps.opacity = fillType.getOpacity();\r
- brushProps.transform = transformToMatrix (fillType.transform.followedBy (transform));\r
+ D2D1_BRUSH_PROPERTIES brushProps = { fillType.getOpacity(), transformToMatrix (fillType.transform.followedBy (transform)) };\r
\r
const int numColors = fillType.gradient->getNumColours();\r
\r
{\r
radialGradient = nullptr;\r
\r
- const Point<float> p1 = fillType.gradient->point1;\r
- const Point<float> p2 = fillType.gradient->point2;\r
- float r = p1.getDistanceFrom(p2);\r
-\r
- D2D1_RADIAL_GRADIENT_BRUSH_PROPERTIES props =\r
- D2D1::RadialGradientBrushProperties(D2D1::Point2F(p1.x, p1.y),\r
- D2D1::Point2F(0, 0),\r
- r, r);\r
+ const auto p1 = fillType.gradient->point1;\r
+ const auto p2 = fillType.gradient->point2;\r
+ const auto r = p1.getDistanceFrom(p2);\r
+ const auto props = D2D1::RadialGradientBrushProperties ({ p1.x, p1.y }, {}, r, r);\r
\r
- owner.pimpl->renderingTarget->CreateRadialGradientBrush(props, brushProps, gradientStops, radialGradient.resetAndGetPointerAddress());\r
+ owner.pimpl->renderingTarget->CreateRadialGradientBrush (props, brushProps, gradientStops, radialGradient.resetAndGetPointerAddress());\r
currentBrush = radialGradient;\r
}\r
else\r
{\r
linearGradient = 0;\r
\r
- const Point<float> p1 = fillType.gradient->point1;\r
- const Point<float> p2 = fillType.gradient->point2;\r
-\r
- D2D1_LINEAR_GRADIENT_BRUSH_PROPERTIES props =\r
- D2D1::LinearGradientBrushProperties(D2D1::Point2F(p1.x, p1.y),\r
- D2D1::Point2F(p2.x, p2.y));\r
+ const auto p1 = fillType.gradient->point1;\r
+ const auto p2 = fillType.gradient->point2;\r
+ const auto props = D2D1::LinearGradientBrushProperties ({ p1.x, p1.y }, { p2.x, p2.y });\r
\r
owner.pimpl->renderingTarget->CreateLinearGradientBrush (props, brushProps, gradientStops, linearGradient.resetAndGetPointerAddress());\r
\r
AffineTransform transform;\r
\r
Font font;\r
- float fontHeightToEmSizeFactor = 1.0;\r
+ float fontHeightToEmSizeFactor = 1.0f;\r
\r
IDWriteFontFace* currentFontFace = nullptr;\r
ComSmartPtr<IDWriteFontFace> localFontFace;\r
D2D1_SIZE_U size = { (UINT32) (windowRect.right - windowRect.left), (UINT32) (windowRect.bottom - windowRect.top) };\r
bounds.setSize (size.width, size.height);\r
\r
- D2D1_RENDER_TARGET_PROPERTIES props = D2D1::RenderTargetProperties();\r
- D2D1_HWND_RENDER_TARGET_PROPERTIES propsHwnd = D2D1::HwndRenderTargetProperties (hwnd, size);\r
-\r
if (pimpl->factories->d2dFactory != nullptr)\r
{\r
- HRESULT hr = pimpl->factories->d2dFactory->CreateHwndRenderTarget (props, propsHwnd, pimpl->renderingTarget.resetAndGetPointerAddress());\r
+ auto hr = pimpl->factories->d2dFactory->CreateHwndRenderTarget ({}, { hwnd, size }, pimpl->renderingTarget.resetAndGetPointerAddress());\r
jassert (SUCCEEDED (hr)); ignoreUnused (hr);\r
hr = pimpl->renderingTarget->CreateSolidColorBrush (D2D1::ColorF::ColorF (0.0f, 0.0f, 0.0f, 1.0f), pimpl->colourBrush.resetAndGetPointerAddress());\r
}\r
void Direct2DLowLevelGraphicsContext::end()\r
{\r
states.clear();\r
- currentState = 0;\r
+ currentState = nullptr;\r
pimpl->renderingTarget->EndDraw();\r
pimpl->renderingTarget->CheckWindowState();\r
}\r
\r
bool Direct2DLowLevelGraphicsContext::clipRegionIntersects (const Rectangle<int>& r)\r
{\r
- return currentState->clipRect.intersects (r.toFloat().transformed (currentState->transform).getSmallestIntegerContainer());\r
+ return currentState->clipRect.intersects (r.toFloat().transformedBy (currentState->transform).getSmallestIntegerContainer());\r
}\r
\r
Rectangle<int> Direct2DLowLevelGraphicsContext::getClipBounds() const\r
{\r
// xxx could this take into account complex clip regions?\r
- return currentState->clipRect.toFloat().transformed (currentState->transform.inverted()).getSmallestIntegerContainer();\r
+ return currentState->clipRect.toFloat().transformedBy (currentState->transform.inverted()).getSmallestIntegerContainer();\r
}\r
\r
bool Direct2DLowLevelGraphicsContext::isClipEmpty() const\r
\r
void Direct2DLowLevelGraphicsContext::restoreState()\r
{\r
- jassert (states.size() > 1); //you should never pop the last state!\r
+ jassert (states.size() > 1); //you should never pop the last state!\r
states.removeLast (1);\r
currentState = states.getLast();\r
}\r
{\r
pimpl->renderingTarget->SetTransform (transformToMatrix (transform.followedBy (currentState->transform)));\r
\r
- D2D1_SIZE_U size;\r
- size.width = image.getWidth();\r
- size.height = image.getHeight();\r
-\r
- D2D1_BITMAP_PROPERTIES bp = D2D1::BitmapProperties();\r
+ D2D1_SIZE_U size = { (UINT32) image.getWidth(), (UINT32) image.getHeight() };\r
+ auto bp = D2D1::BitmapProperties();\r
\r
Image img (image.convertedToFormat (Image::ARGB));\r
Image::BitmapData bd (img, Image::BitmapData::readOnly);\r
currentState->createBrush();\r
currentState->createFont();\r
\r
- float hScale = currentState->font.getHorizontalScale();\r
+ auto hScale = currentState->font.getHorizontalScale();\r
\r
pimpl->renderingTarget->SetTransform (transformToMatrix (AffineTransform::scale (hScale, 1.0f)\r
.followedBy (transform)\r
.followedBy (currentState->transform)));\r
\r
- const UINT16 glyphIndices = (UINT16) glyphNumber;\r
- const FLOAT glyphAdvances = 0;\r
- DWRITE_GLYPH_OFFSET offset;\r
- offset.advanceOffset = 0;\r
- offset.ascenderOffset = 0;\r
+ const auto glyphIndices = (UINT16) glyphNumber;\r
+ const auto glyphAdvances = 0.0f;\r
+ DWRITE_GLYPH_OFFSET offset = { 0.0f, 0.0f };\r
\r
DWRITE_GLYPH_RUN glyphRun;\r
glyphRun.fontFace = currentState->currentFontFace;\r
glyphRun.isSideways = FALSE;\r
glyphRun.bidiLevel = 0;\r
\r
- pimpl->renderingTarget->DrawGlyphRun (D2D1::Point2F (0, 0), &glyphRun, currentState->currentBrush);\r
+ pimpl->renderingTarget->DrawGlyphRun ({}, &glyphRun, currentState->currentBrush);\r
pimpl->renderingTarget->SetTransform (D2D1::IdentityMatrix());\r
}\r
\r
\r
switch (text.getJustification().getOnlyHorizontalFlags())\r
{\r
+ case 0:\r
case Justification::left: break;\r
case Justification::right: alignment = DWRITE_TEXT_ALIGNMENT_TRAILING; break;\r
case Justification::horizontallyCentred: alignment = DWRITE_TEXT_ALIGNMENT_CENTER; break;\r
\r
switch (text.getJustification().getOnlyHorizontalFlags())\r
{\r
+ case 0:\r
case Justification::left: alignment = DWRITE_TEXT_ALIGNMENT_TRAILING; break;\r
case Justification::right: alignment = DWRITE_TEXT_ALIGNMENT_LEADING; break;\r
default: break;\r
col.getFloatAlpha()),\r
d2dBrush.resetAndGetPointerAddress());\r
\r
- // We need to call SetDrawingEffect with a legimate brush to get DirectWrite to break text based on colours\r
+ // We need to call SetDrawingEffect with a legitimate brush to get DirectWrite to break text based on colours\r
textLayout.SetDrawingEffect (d2dBrush, range);\r
}\r
}\r
@param buttonName the text to put in the button (the component's name is also\r
initially set to this string, but these can be changed later\r
using the setName() and setButtonText() methods)\r
- @param toolTip an optional string to use as a toolip\r
+ @param toolTip an optional string to use as a tooltip\r
*/\r
TextButton (const String& buttonName, const String& toolTip);\r
\r
: cachedImage->invalidate (area)))\r
return;\r
\r
+ if (area.isEmpty())\r
+ return;\r
+\r
if (flags.hasHeavyweightPeerFlag)\r
{\r
if (auto* peer = getPeer())\r
}\r
else\r
{\r
- g.saveState();\r
+ Graphics::ScopedSaveState ss (g);\r
\r
if (! (ComponentHelpers::clipObscuredRegions (*this, g, clipBounds, {}) && g.isClipEmpty()))\r
paint (g);\r
-\r
- g.restoreState();\r
}\r
\r
for (int i = 0; i < childComponentList.size(); ++i)\r
{\r
if (child.affineTransform != nullptr)\r
{\r
- g.saveState();\r
+ Graphics::ScopedSaveState ss (g);\r
+\r
g.addTransform (*child.affineTransform);\r
\r
if ((child.flags.dontClipGraphicsFlag && ! g.isClipEmpty()) || g.reduceClipRegion (child.getBounds()))\r
child.paintWithinParentContext (g);\r
-\r
- g.restoreState();\r
}\r
else if (clipBounds.intersects (child.getBounds()))\r
{\r
- g.saveState();\r
+ Graphics::ScopedSaveState ss (g);\r
\r
if (child.flags.dontClipGraphicsFlag)\r
{\r
if (nothingClipped || ! g.isClipEmpty())\r
child.paintWithinParentContext (g);\r
}\r
-\r
- g.restoreState();\r
}\r
}\r
}\r
\r
- g.saveState();\r
+ Graphics::ScopedSaveState ss (g);\r
paintOverChildren (g);\r
- g.restoreState();\r
}\r
\r
void Component::paintEntireComponent (Graphics& g, bool ignoreAlphaLevel)\r
paintComponentAndChildren (g2);\r
}\r
\r
- g.saveState();\r
+ Graphics::ScopedSaveState ss (g);\r
+\r
g.addTransform (AffineTransform::scale (1.0f / scale));\r
effect->applyEffect (effectImage, g, scale, ignoreAlphaLevel ? 1.0f : getAlpha());\r
- g.restoreState();\r
}\r
else if (componentTransparency > 0 && ! ignoreAlphaLevel)\r
{\r
/** Destructor.\r
\r
Note that when a component is deleted, any child components it contains are NOT\r
- automatically deleted. It's your responsibilty to manage their lifespan - you\r
+ automatically deleted. It's your responsibility to manage their lifespan - you\r
may want to use helper methods like deleteAllChildren(), or less haphazard\r
approaches like using std::unique_ptrs or normal object aggregation to manage them.\r
\r
a screen coordinate.\r
\r
If you've used setTransform() to apply one or more transforms to components, then the source rectangle\r
- may not actually be rectanglular when converted to the target space, so in that situation this will return\r
+ may not actually be rectangular when converted to the target space, so in that situation this will return\r
the smallest rectangle that fully contains the transformed area.\r
*/\r
Rectangle<int> getLocalArea (const Component* sourceComponent,\r
/** Converts a rectangle from this component's coordinate space to a screen coordinate.\r
\r
If you've used setTransform() to apply one or more transforms to components, then the source rectangle\r
- may not actually be rectanglular when converted to the target space, so in that situation this will return\r
+ may not actually be rectangular when converted to the target space, so in that situation this will return\r
the smallest rectangle that fully contains the transformed area.\r
@see getLocalPoint, localPointToGlobal\r
*/\r
virtual void enablementChanged();\r
\r
//==============================================================================\r
- /** Returns the component's current transparancy level.\r
+ /** Returns the component's current transparency level.\r
See setAlpha() for more details.\r
*/\r
float getAlpha() const noexcept;\r
DrawableComposite* getParent() const;\r
\r
/** Sets a the clipping region of this drawable using another drawable.\r
- The drawbale passed in will be deleted when no longer needed.\r
+ The drawable passed in will be deleted when no longer needed.\r
*/\r
void setClipPath (std::unique_ptr<Drawable> drawableClipPath);\r
\r
static Path parseSVGPath (const String& svgPath);\r
\r
//==============================================================================\r
- /** Returns the area that this drawble covers.\r
+ /** Returns the area that this drawable covers.\r
The result is expressed in this drawable's own coordinate space, and does not take\r
into account any transforms that may be applied to the component.\r
*/\r
if (parseCoordsOrSkip (d, p1, false))\r
{\r
String num;\r
+ bool flagValue = false;\r
\r
if (parseNextNumber (d, num, false))\r
{\r
- const float angle = degreesToRadians (num.getFloatValue());\r
+ auto angle = degreesToRadians (num.getFloatValue());\r
\r
- if (parseNextNumber (d, num, false))\r
+ if (parseNextFlag (d, flagValue))\r
{\r
- const bool largeArc = num.getIntValue() != 0;\r
+ auto largeArc = flagValue;\r
\r
- if (parseNextNumber (d, num, false))\r
+ if (parseNextFlag (d, flagValue))\r
{\r
- const bool sweep = num.getIntValue() != 0;\r
+ auto sweep = flagValue;\r
\r
if (parseCoordsOrSkip (d, p2, false))\r
{\r
if (xml->hasTagName ("use"))\r
return useText (xml);\r
\r
- if (! xml->hasTagName ("text"))\r
+ if (! xml->hasTagName ("text") && ! xml->hasTagNameIgnoringNamespace ("tspan"))\r
return nullptr;\r
\r
Array<float> xCoords, yCoords, dxCoords, dyCoords;\r
return true;\r
}\r
\r
+ static bool parseNextFlag (String::CharPointerType& text, bool& value)\r
+ {\r
+ while (text.isWhitespace() || *text == ',')\r
+ ++text;\r
+\r
+ if (*text != '0' && *text != '1')\r
+ return false;\r
+\r
+ value = *(text++) != '0';\r
+\r
+ while (text.isWhitespace() || *text == ',')\r
+ ++text;\r
+\r
+ return true;\r
+ }\r
+\r
//==============================================================================\r
Colour parseColour (const XmlPath& xml, StringRef attributeName, const Colour defaultColour) const\r
{\r
if the user pressed 'ok' rather than cancelling).\r
\r
On mobile platforms, the file browser may return a URL instead of a local file.\r
- Therefore, om mobile platforms, you should call getURLResult() instead.\r
+ Therefore, on mobile platforms, you should call getURLResult() instead.\r
\r
If you're using a multiple-file select, then use the getResults() method instead,\r
to obtain the list of all files chosen.\r
browse method.\r
\r
On mobile platforms, the file browser may return a URL instead of a local file.\r
- Therefore, om mobile platforms, you should call getURLResults() instead.\r
+ Therefore, on mobile platforms, you should call getURLResults() instead.\r
\r
This array may be empty if no files were chosen, or can contain multiple entries\r
if multiple files were chosen.\r
Note: On iOS this will only return true if you have iCloud permissions\r
and code-signing enabled in the Projucer and have added iCloud containers\r
to your app in Apple's online developer portal. Additionally, the user must\r
- have installed the iCloud app on their device and used the app at leat once.\r
+ have installed the iCloud app on their device and used the app at least once.\r
*/\r
static bool isPlatformDialogAvailable();\r
\r
/** Called to indicate that the user's currently selected file has changed.\r
\r
@param newSelectedFile the newly selected file or directory, which may be\r
- a defualt File() object if none is selected.\r
+ a default File() object if none is selected.\r
*/\r
virtual void selectedFileChanged (const File& newSelectedFile) = 0;\r
\r
==============================================================================\r
*/\r
\r
+\r
/*******************************************************************************\r
The block below describes the properties of this module, and is read by\r
the Projucer to automatically generate project code that uses it.\r
\r
BEGIN_JUCE_MODULE_DECLARATION\r
\r
- ID: juce_gui_basics\r
- vendor: juce\r
- version: 5.4.5\r
- name: JUCE GUI core classes\r
- description: Basic user-interface components and related classes.\r
- website: http://www.juce.com/juce\r
- license: GPL/Commercial\r
+ ID: juce_gui_basics\r
+ vendor: juce\r
+ version: 5.4.6\r
+ name: JUCE GUI core classes\r
+ description: Basic user-interface components and related classes.\r
+ website: http://www.juce.com/juce\r
+ license: GPL/Commercial\r
\r
- dependencies: juce_graphics juce_data_structures\r
- OSXFrameworks: Cocoa Carbon QuartzCore\r
- iOSFrameworks: UIKit MobileCoreServices\r
- linuxPackages: x11 xinerama xext\r
+ dependencies: juce_graphics juce_data_structures\r
+ OSXFrameworks: Cocoa Carbon QuartzCore\r
+ iOSFrameworks: UIKit MobileCoreServices\r
+ linuxPackages: x11 xinerama xext\r
\r
END_JUCE_MODULE_DECLARATION\r
\r
return 0;\r
}\r
\r
- #if JUCE_MAC\r
+ #if JUCE_MAC || JUCE_IOS\r
struct OSXSymbolReplacement\r
{\r
const char* text;\r
if (mods.isCtrlDown()) desc << "ctrl + ";\r
if (mods.isShiftDown()) desc << "shift + ";\r
\r
- #if JUCE_MAC\r
+ #if JUCE_MAC || JUCE_IOS\r
if (mods.isAltDown()) desc << "option + ";\r
if (mods.isCommandDown()) desc << "command + ";\r
#else\r
\r
String KeyPress::getTextDescriptionWithIcons() const\r
{\r
- #if JUCE_MAC\r
+ #if JUCE_MAC || JUCE_IOS\r
auto s = getTextDescription();\r
\r
for (int i = 0; i < numElementsInArray (KeyPressHelpers::osxSymbols); ++i)\r
/** Creates a KeyPress for a key and some modifiers.\r
\r
e.g.\r
- CTRL+C would be: KeyPress ('c', ModifierKeys::ctrlModifier)\r
- SHIFT+Escape would be: KeyPress (KeyPress::escapeKey, ModifierKeys::shiftModifier)\r
+ CTRL+C would be: KeyPress ('c', ModifierKeys::ctrlModifier, 0)\r
+ SHIFT+Escape would be: KeyPress (KeyPress::escapeKey, ModifierKeys::shiftModifier, 0)\r
\r
@param keyCode a code that represents the key - this value must be\r
one of special constants listed in this class, or an\r
/** Checks whether the 'command' key flag is set (or 'ctrl' on Windows/Linux).\r
\r
This is a platform-agnostic way of checking for the operating system's\r
- preferred command-key modifier - so on the Mac it tests for the Apple key, on\r
+ preferred command-key modifier - so on the Mac it tests for the cmd key, on\r
Windows/Linux, it's actually checking for the CTRL key.\r
*/\r
inline bool isCommandDown() const noexcept { return testFlags (commandModifier); }\r
/** Middle mouse button flag. */\r
middleButtonModifier = 64,\r
\r
- #if JUCE_MAC\r
+ #if JUCE_MAC || JUCE_IOS\r
/** Command key flag - on windows this is the same as the CTRL key flag. */\r
commandModifier = 8,\r
\r
public:\r
AnimationTask (Component* c) noexcept : component (c) {}\r
\r
+ ~AnimationTask()\r
+ {\r
+ proxy.deleteAndZero();\r
+ }\r
+\r
void reset (const Rectangle<int>& finalBounds,\r
float finalAlpha,\r
int millisecondsToSpendMoving,\r
midSpeed = invTotalDistance;\r
endSpeed = jmax (0.0, endSpd * invTotalDistance);\r
\r
+ proxy.deleteAndZero();\r
+\r
if (useProxyComponent)\r
- proxy.reset (new ProxyComponent (*component));\r
- else\r
- proxy.reset();\r
+ proxy = new ProxyComponent (*component);\r
\r
component->setVisible (! useProxyComponent);\r
}\r
\r
bool useTimeslice (const int elapsed)\r
{\r
- if (auto* c = proxy != nullptr ? proxy.get()\r
+ if (auto* c = proxy != nullptr ? proxy.getComponent()\r
: component.get())\r
{\r
msElapsed += elapsed;\r
else\r
jassertfalse; // seem to be trying to animate a component that's not visible..\r
\r
- auto scale = (float) Desktop::getInstance().getDisplays().findDisplayForRect (getScreenBounds()).scale;\r
+ auto scale = (float) Desktop::getInstance().getDisplays().findDisplayForRect (getScreenBounds()).scale\r
+ * Component::getApproximateScaleFactorForComponent (&c);\r
\r
image = c.createComponentSnapshot (c.getLocalBounds(), false, scale);\r
\r
};\r
\r
WeakReference<Component> component;\r
- std::unique_ptr<Component> proxy;\r
+ Component::SafePointer<Component> proxy;\r
\r
Rectangle<int> destination;\r
double destAlpha;\r
\r
void mouseDrag (const MouseEvent& e) override\r
{\r
- ConcertinaPanel& panel = getPanel();\r
- panel.setLayout (dragStartSizes.withMovedPanel (panel.holders.indexOf (this),\r
- mouseDownY + e.getDistanceFromDragStartY(),\r
- panel.getHeight()), false);\r
+ if (e.mouseWasDraggedSinceMouseDown())\r
+ {\r
+ auto& panel = getPanel();\r
+ panel.setLayout (dragStartSizes.withMovedPanel (panel.holders.indexOf (this),\r
+ mouseDownY + e.getDistanceFromDragStartY(),\r
+ panel.getHeight()), false);\r
+ }\r
}\r
\r
void mouseDoubleClick (const MouseEvent&) override\r
\r
Rectangle<int> SidePanel::calculateBoundsInParent (Component& parentComp) const\r
{\r
- auto parentBounds = parentComp.getBounds();\r
+ auto parentBounds = parentComp.getLocalBounds();\r
\r
if (isOnLeft)\r
{\r
auto oldContentBounds = contentComp->getBounds();\r
contentHolder.setBounds (contentArea);\r
\r
- // If the content has changed its size, that might affect our scrollbars, so go round again and re-caclulate..\r
+ // If the content has changed its size, that might affect our scrollbars, so go round again and re-calculate..\r
if (oldContentBounds == contentComp->getBounds())\r
break;\r
}\r
hbar.setRangeLimits (0.0, contentBounds.getWidth());\r
hbar.setCurrentRange (visibleOrigin.x, contentArea.getWidth());\r
hbar.setSingleStepSize (singleStepX);\r
- hbar.cancelPendingUpdate();\r
\r
if (canShowHBar && ! hBarVisible)\r
visibleOrigin.setX (0);\r
vbar.setRangeLimits (0.0, contentBounds.getHeight());\r
vbar.setCurrentRange (visibleOrigin.y, contentArea.getHeight());\r
vbar.setSingleStepSize (singleStepY);\r
- vbar.cancelPendingUpdate();\r
\r
if (canShowVBar && ! vBarVisible)\r
visibleOrigin.setY (0);\r
/* if this fails it means you're trying to create a LookAndFeel object before\r
the static Colours have been initialised. That ain't gonna work. It probably\r
means that you're using a static LookAndFeel object and that your compiler has\r
- decided to intialise it before the Colours class.\r
+ decided to initialise it before the Colours class.\r
*/\r
jassert (Colours::white == Colour (0xffffffff));\r
\r
g.setGradientFill (ColourGradient (Colour (0x10000000), gx1, gy1,\r
Colours::transparentBlack, gx2, gy2, false));\r
\r
- g.saveState();\r
+ {\r
+ Graphics::ScopedSaveState ss (g);\r
\r
- if (isScrollbarVertical)\r
- g.reduceClipRegion (x + width / 2, y, width, height);\r
- else\r
- g.reduceClipRegion (x, y + height / 2, width, height);\r
+ if (isScrollbarVertical)\r
+ g.reduceClipRegion (x + width / 2, y, width, height);\r
+ else\r
+ g.reduceClipRegion (x, y + height / 2, width, height);\r
\r
- g.fillPath (thumbPath);\r
- g.restoreState();\r
+ g.fillPath (thumbPath);\r
+ }\r
\r
g.setColour (Colour (0x4c000000));\r
g.strokePath (thumbPath, PathStrokeType (0.4f));\r
const Rectangle<int> fullSize (0, 0, w, h);\r
auto centreArea = border.subtractedFrom (fullSize);\r
\r
- g.saveState();\r
+ Graphics::ScopedSaveState ss (g);\r
+\r
g.excludeClipRegion (centreArea);\r
\r
g.setColour (Colour (0x50000000));\r
\r
g.setColour (Colour (0x19000000));\r
g.drawRect (centreArea.expanded (1, 1));\r
-\r
- g.restoreState();\r
}\r
}\r
\r
if (g.clipRegionIntersects (Rectangle<int> (x, y, width, height)))\r
{\r
auto& context = g.getInternalContext();\r
- context.saveState();\r
+ Graphics::ScopedSaveState ss (g);\r
\r
for (int i = bevelThickness; --i >= 0;)\r
{\r
context.setFill (bottomRightColour.withMultipliedAlpha (op * 0.75f));\r
context.fillRect (Rectangle<int> (x + width - i - 1, y + i + 1, 1, height - i * 2 - 2), false);\r
}\r
-\r
- context.restoreState();\r
}\r
}\r
\r
\r
if (! (flatOnLeft || flatOnTop || flatOnBottom))\r
{\r
- g.saveState();\r
+ Graphics::ScopedSaveState ss (g);\r
+\r
g.setGradientFill (cg);\r
g.reduceClipRegion (intX, intY, intEdge, intH);\r
g.fillPath (outline);\r
- g.restoreState();\r
}\r
\r
if (! (flatOnRight || flatOnTop || flatOnBottom))\r
cg.point1.setX (x + width - edgeBlurRadius);\r
cg.point2.setX (x + width);\r
\r
- g.saveState();\r
+ Graphics::ScopedSaveState ss (g);\r
+\r
g.setGradientFill (cg);\r
g.reduceClipRegion (intX + intW - intEdge, intY, 2 + intEdge, intH);\r
g.fillPath (outline);\r
- g.restoreState();\r
}\r
\r
{\r
setName (name);\r
}\r
\r
- void paint (Graphics& g) override\r
- {\r
- getLookAndFeel().drawPopupMenuSectionHeader (g, getLocalBounds(), getName());\r
- }\r
+ void paint (Graphics& g) override;\r
\r
void getIdealSize (int& idealWidth, int& idealHeight) override\r
{\r
addMouseListener (&parent, false);\r
}\r
\r
- ~ItemComponent() override\r
- {\r
- if (customComp != nullptr)\r
- setItem (*customComp, nullptr);\r
-\r
- removeChildComponent (customComp.get());\r
- }\r
+ ~ItemComponent() override;\r
\r
void getIdealSize (int& idealWidth, int& idealHeight, const int standardItemHeight)\r
{\r
getMouseState (Desktop::getInstance().getMainMouseSource()); // forces creation of a mouse source watcher for the main mouse\r
}\r
\r
- ~MenuWindow() override\r
- {\r
- getActiveWindows().removeFirstMatchingValue (this);\r
- Desktop::getInstance().removeGlobalMouseListener (this);\r
- activeSubMenu.reset();\r
- items.clear();\r
- }\r
+ ~MenuWindow() override;\r
\r
//==============================================================================\r
void paint (Graphics& g) override\r
\r
if (componentAttachedTo->reallyContains (mousePos, true))\r
{\r
- postCommandMessage (PopupMenuSettings::dismissCommandId); // dismiss asynchrounously\r
+ postCommandMessage (PopupMenuSettings::dismissCommandId); // dismiss asynchronously\r
return;\r
}\r
}\r
if (relativeTo != nullptr)\r
targetPoint = relativeTo->localPointToGlobal (targetPoint);\r
\r
- auto parentArea = Desktop::getInstance().getDisplays().findDisplayForPoint (targetPoint)\r
+ auto parentArea = Desktop::getInstance().getDisplays().findDisplayForPoint (targetPoint * scaleFactor)\r
#if JUCE_MAC || JUCE_ANDROID\r
.userArea;\r
#else\r
startTimerHz (20);\r
}\r
\r
- void handleMouseEvent (const MouseEvent& e)\r
- {\r
- if (! window.windowIsStillValid())\r
- return;\r
-\r
- startTimerHz (20);\r
- handleMousePosition (e.getScreenPosition());\r
- }\r
+ void handleMouseEvent (const MouseEvent& e);\r
\r
void timerCallback() override\r
{\r
addAndMakeVisible (comp);\r
}\r
\r
- void getIdealSize (int& idealWidth, int& idealHeight) override\r
- {\r
- idealWidth = width;\r
- idealHeight = height;\r
- }\r
+ void getIdealSize (int& idealWidth, int& idealHeight) override;\r
\r
void resized() override\r
{\r
\r
};\r
\r
+// The following implementations are outside of the class definitions to avoid spurious\r
+// warning messages when dynamically loading libraries at runtime on macOS\r
+void PopupMenu::HelperClasses::HeaderItemComponent::paint (Graphics& g)\r
+{\r
+ getLookAndFeel().drawPopupMenuSectionHeader (g, getLocalBounds(), getName());\r
+}\r
+\r
+PopupMenu::HelperClasses::ItemComponent::~ItemComponent()\r
+{\r
+ if (customComp != nullptr)\r
+ setItem (*customComp, nullptr);\r
+\r
+ removeChildComponent (customComp.get());\r
+}\r
+\r
+PopupMenu::HelperClasses::MenuWindow::~MenuWindow()\r
+{\r
+ getActiveWindows().removeFirstMatchingValue (this);\r
+ Desktop::getInstance().removeGlobalMouseListener (this);\r
+ activeSubMenu.reset();\r
+ items.clear();\r
+}\r
+\r
+void PopupMenu::HelperClasses::MouseSourceState::handleMouseEvent (const MouseEvent& e)\r
+{\r
+ if (! window.windowIsStillValid())\r
+ return;\r
+\r
+ startTimerHz (20);\r
+ handleMousePosition (e.getScreenPosition());\r
+}\r
+\r
+void PopupMenu::HelperClasses::NormalComponentWrapper::getIdealSize (int& idealWidth, int& idealHeight)\r
+{\r
+ idealWidth = width;\r
+ idealHeight = height;\r
+}\r
+\r
//==============================================================================\r
PopupMenu::PopupMenu()\r
{\r
return *this;\r
}\r
\r
+PopupMenu::Item& PopupMenu::Item::setImage (std::unique_ptr<Drawable> newImage) & noexcept\r
+{\r
+ image = std::move (newImage);\r
+ return *this;\r
+}\r
+\r
PopupMenu::Item&& PopupMenu::Item::setTicked (bool shouldBeTicked) && noexcept\r
{\r
isTicked = shouldBeTicked;\r
return std::move (*this);\r
}\r
\r
+PopupMenu::Item&& PopupMenu::Item::setImage (std::unique_ptr<Drawable> newImage) && noexcept\r
+{\r
+ image = std::move (newImage);\r
+ return std::move (*this);\r
+}\r
+\r
void PopupMenu::addItem (Item newItem)\r
{\r
// An ID of 0 is used as a return value to indicate that the user\r
Item& setColour (Colour) & noexcept;\r
/** Sets the customComponent property (and returns a reference to this item to allow chaining). */\r
Item& setCustomComponent (ReferenceCountedObjectPtr<CustomComponent> customComponent) & noexcept;\r
+ /** Sets the image property (and returns a reference to this item to allow chaining). */\r
+ Item& setImage (std::unique_ptr<Drawable>) & noexcept;\r
\r
/** Sets the isTicked flag (and returns a reference to this item to allow chaining). */\r
Item&& setTicked (bool shouldBeTicked = true) && noexcept;\r
Item&& setColour (Colour) && noexcept;\r
/** Sets the customComponent property (and returns a reference to this item to allow chaining). */\r
Item&& setCustomComponent (ReferenceCountedObjectPtr<CustomComponent> customComponent) && noexcept;\r
+ /** Sets the image property (and returns a reference to this item to allow chaining). */\r
+ Item&& setImage (std::unique_ptr<Drawable>) && noexcept;\r
};\r
\r
/** Adds an item to the menu.\r
\r
/** Appends a separator to the menu, to help break it up into sections.\r
The menu class is smart enough not to display separators at the top or bottom\r
- of the menu, and it will replace mutliple adjacent separators with a single\r
+ of the menu, and it will replace multiple adjacent separators with a single\r
one, so your code can be quite free and easy about adding these, and it'll\r
always look ok.\r
*/\r
@param e the current mouse-drag event\r
@param constrainer an optional constrainer object that should be used\r
to apply limits to the component's position. Pass\r
- null if you don't want to contrain the movement.\r
+ null if you don't want to constrain the movement.\r
@see startDraggingComponent\r
*/\r
void dragComponent (Component* componentToDrag,\r
}\r
}\r
\r
+ dragImageComponent->sourceDetails.localPosition = sourceComponent->getLocalPoint (nullptr, lastMouseDown);\r
dragImageComponent->updateLocation (false, lastMouseDown);\r
\r
#if JUCE_WINDOWS\r
dragged.\r
\r
@param dragSourceDetails contains information about the source of the drag operation.\r
- @returns true if this component wants to receive the other callbacks regarging this\r
+ @returns true if this component wants to receive the other callbacks regarding this\r
type of object; if it returns false, no other callbacks will be made.\r
*/\r
virtual bool isInterestedInDragSource (const SourceDetails& dragSourceDetails) = 0;\r
inside them!\r
\r
@param files the set of (absolute) pathnames of the files that the user is dragging\r
- @returns true if this component wants to receive the other callbacks regarging this\r
+ @returns true if this component wants to receive the other callbacks regarding this\r
type of object; if it returns false, no other callbacks will be made.\r
*/\r
virtual bool isInterestedInFileDrag (const StringArray& files) = 0;\r
ParentCursor = 0, /**< Indicates that the component's parent's cursor should be used. */\r
\r
NoCursor, /**< An invisible cursor. */\r
- NormalCursor, /**< The stardard arrow cursor. */\r
+ NormalCursor, /**< The standard arrow cursor. */\r
\r
WaitCursor, /**< The normal hourglass or spinning-beachball 'busy' cursor. */\r
IBeamCursor, /**< A vertical I-beam for positioning within text. */\r
/** If true, then the wheel has continuous, un-stepped motion. */\r
bool isSmooth;\r
\r
- /** If true, then this event is part of the intertial momentum phase that follows\r
+ /** If true, then this event is part of the inertial momentum phase that follows\r
the wheel being released. */\r
bool isInertial;\r
};\r
Each MouseEvent object contains a reference to the MouseInputSource that generated\r
it. In an environment with a single mouse for input, all events will come from the\r
same source, but in a multi-touch system, there may be multiple MouseInputSource\r
- obects active, each representing a stream of events coming from a particular finger.\r
+ objects active, each representing a stream of events coming from a particular finger.\r
\r
Events coming from a single MouseInputSource are always sent in a fixed and predictable\r
order: a mouseMove will never be called without a mouseEnter having been sent beforehand,\r
component, so don't do anything time-consuming in here!\r
\r
@param text the text that the user is dragging\r
- @returns true if this component wants to receive the other callbacks regarging this\r
+ @returns true if this component wants to receive the other callbacks regarding this\r
type of object; if it returns false, no other callbacks will be made.\r
*/\r
virtual bool isInterestedInTextDrag (const String& text) = 0;\r
// This byte-code is generated from native/javacore/app/com/roli/juce/JuceSharingContentProvider.java with min sdk version 16\r
// See juce_core/native/java/README.txt on how to generate this byte-code.\r
static const uint8 javaJuceSharingContentProvider[] =\r
-{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,\r
-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,\r
-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,\r
-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,\r
-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,\r
-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,\r
-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,\r
-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,\r
-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,\r
-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,\r
-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,\r
-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,\r
-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,\r
-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,\r
-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,\r
-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,\r
-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,\r
-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,\r
-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,\r
-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,\r
-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,\r
-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,\r
-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,\r
-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,\r
-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,\r
-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,\r
-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,\r
-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,\r
-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,\r
-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,\r
-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,\r
-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,\r
-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,\r
-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,\r
-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,\r
-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,\r
-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,\r
-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,\r
-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,\r
-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,\r
-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,\r
-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,\r
-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,\r
-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,\r
-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,\r
-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,\r
-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,\r
-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,\r
-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,\r
-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,\r
-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,\r
-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,\r
-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,\r
-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,\r
-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,\r
-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,\r
-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,\r
-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,\r
-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,\r
-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,\r
-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,\r
-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,\r
-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,\r
-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,\r
-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,\r
-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,\r
-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,\r
-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,\r
-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,\r
-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,\r
-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,\r
-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,\r
-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,\r
-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,\r
-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,\r
-12,0,0,0,16,0,0,1,0,0,0,160,12,0,0,0,0};\r
+{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,\r
+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,\r
+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,\r
+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,\r
+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,\r
+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,\r
+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,\r
+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,\r
+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,\r
+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,\r
+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,\r
+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,\r
+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,\r
+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,\r
+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,\r
+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,\r
+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,\r
+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,\r
+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,\r
+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,\r
+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,\r
+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,\r
+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,\r
+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,\r
+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,\r
+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,\r
+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,\r
+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,\r
+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,\r
+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,\r
+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,\r
+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,\r
+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,\r
+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,\r
+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,\r
+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,\r
+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,\r
+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,\r
+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,\r
+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,\r
+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,\r
+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,\r
+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,\r
+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,\r
+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,\r
+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,\r
+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,\r
+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,\r
+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,\r
+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,\r
+241,33,100,13,0,0,0,0};\r
\r
//==============================================================================\r
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \\r
extern void juce_firebaseRemoteMessageSendError (void*, void*);\r
#endif\r
\r
-#if JUCE_IN_APP_PURCHASES && JUCE_MODULE_AVAILABLE_juce_product_unlocking\r
- extern void juce_inAppPurchaseCompleted (void*);\r
-#endif\r
-\r
extern void juce_contentSharingCompleted (int);\r
\r
//==============================================================================\r
\r
if (auto* parentController = peer->controller)\r
[parentController showViewController: controller.get() sender: parentController];\r
-\r
- if (peer->view.window != nil)\r
- peer->view.window.autoresizesSubviews = YES;\r
}\r
}\r
\r
\r
if (auto* parentController = peer->controller)\r
[parentController showViewController: controller.get() sender: parentController];\r
-\r
- if (peer->view.window != nil)\r
- peer->view.window.autoresizesSubviews = YES;\r
}\r
}\r
\r
window.rootViewController = controller;\r
\r
window.hidden = true;\r
- window.autoresizesSubviews = NO;\r
window.transform = Orientations::getCGTransformFor (Desktop::getInstance().getCurrentOrientation());\r
window.opaque = component.isOpaque();\r
window.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent: 0];\r
ScopedXLock xlock (display);\r
XGetInputFocus (display, &focusedWindow, &revert);\r
\r
+ if (focusedWindow == PointerRoot)\r
+ return false;\r
+\r
return isParentWindowOf (focusedWindow);\r
}\r
\r
==============================================================================\r
*/\r
\r
+//==============================================================================\r
+#if defined (MAC_OS_X_VERSION_10_8) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_8) \\r
+ && USE_COREGRAPHICS_RENDERING && JUCE_COREGRAPHICS_DRAW_ASYNC\r
+static const juce::Identifier disableAsyncLayerBackedViewIdentifier { "disableAsyncLayerBackedView" };\r
+\r
+void setComponentAsyncLayerBackedViewDisabled (juce::Component& comp, bool shouldDisableAsyncLayerBackedView)\r
+{\r
+ comp.getProperties().set (disableAsyncLayerBackedViewIdentifier, shouldDisableAsyncLayerBackedView);\r
+}\r
+\r
+bool getComponentAsyncLayerBackedViewDisabled (juce::Component& comp)\r
+{\r
+ return comp.getProperties()[disableAsyncLayerBackedViewIdentifier];\r
+}\r
+#endif\r
+\r
+//==============================================================================\r
namespace juce\r
{\r
typedef void (*AppFocusChangeCallback)();\r
\r
[view setPostsFrameChangedNotifications: YES];\r
\r
+ #if defined (MAC_OS_X_VERSION_10_8) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_8) \\r
+ && USE_COREGRAPHICS_RENDERING && JUCE_COREGRAPHICS_DRAW_ASYNC\r
+ if (! getComponentAsyncLayerBackedViewDisabled (component))\r
+ {\r
+ [view setWantsLayer: YES];\r
+ [[view layer] setDrawsAsynchronously: YES];\r
+ }\r
+ #endif\r
+\r
if (isSharedWindow)\r
{\r
window = [viewToAttachTo window];\r
\r
[window setOpaque: component.isOpaque()];\r
\r
- #if defined (MAC_OS_X_VERSION_10_14) && (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_14)\r
if (! [window isOpaque])\r
[window setBackgroundColor: [NSColor clearColor]];\r
\r
- #if defined (MAC_OS_X_VERSION_10_9) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_9)\r
- [view setAppearance: [NSAppearance appearanceNamed: NSAppearanceNameAqua]];\r
- #endif\r
+ #if defined (MAC_OS_X_VERSION_10_9) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_9)\r
+ [view setAppearance: [NSAppearance appearanceNamed: NSAppearanceNameAqua]];\r
#endif\r
\r
[window setHasShadow: ((windowStyleFlags & windowHasDropShadow) != 0)];\r
\r
// When windows are being resized, artificially throttling high-frequency repaints helps\r
// to stop the event queue getting clogged, and keeps everything working smoothly.\r
- // For some reason Logic also needs this throttling to recored parameter events correctly.\r
+ // For some reason Logic also needs this throttling to record parameter events correctly.\r
if (msSinceLastRepaint < minimumRepaintInterval && shouldThrottleRepaint())\r
{\r
startTimer (static_cast<int> (minimumRepaintInterval - msSinceLastRepaint));\r
\r
bool canBecomeKeyWindow()\r
{\r
- return (getStyleFlags() & juce::ComponentPeer::windowIgnoresKeyPresses) == 0;\r
+ return component.isVisible() && (getStyleFlags() & juce::ComponentPeer::windowIgnoresKeyPresses) == 0;\r
}\r
\r
bool canBecomeMainWindow()\r
{\r
- return dynamic_cast<ResizableWindow*> (&component) != nullptr;\r
+ return component.isVisible() && dynamic_cast<ResizableWindow*> (&component) != nullptr;\r
}\r
\r
bool worksWhenModal() const\r
static BOOL becomeFirstResponder (id self, SEL)\r
{\r
if (auto* owner = getOwner (self))\r
- owner->viewFocusGain();\r
+ {\r
+ if (owner->canBecomeKeyWindow())\r
+ {\r
+ owner->viewFocusGain();\r
+ return YES;\r
+ }\r
+ }\r
\r
- return YES;\r
+ return NO;\r
}\r
\r
static BOOL resignFirstResponder (id self, SEL)\r
sendSuperclassMessage (self, @selector (becomeKeyWindow));\r
\r
if (auto* owner = getOwner (self))\r
- owner->becomeKeyWindow();\r
+ {\r
+ if (owner->canBecomeKeyWindow())\r
+ {\r
+ owner->becomeKeyWindow();\r
+ return;\r
+ }\r
+\r
+ // this fixes a bug causing hidden windows to sometimes become visible when the app regains focus\r
+ if (! owner->getComponent().isVisible())\r
+ [(NSWindow*) self orderOut: nil];\r
+ }\r
}\r
\r
static BOOL windowShouldClose (id self, SEL, id /*window*/)\r
static void selectImageForDrawing (const Image& image)\r
{\r
[NSGraphicsContext saveGraphicsState];\r
+\r
+ #if (defined (MAC_OS_X_VERSION_10_10) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_10)\r
[NSGraphicsContext setCurrentContext: [NSGraphicsContext graphicsContextWithCGContext: juce_getImageContext (image)\r
flipped: false]];\r
+ #else\r
+ [NSGraphicsContext setCurrentContext: [NSGraphicsContext graphicsContextWithGraphicsPort: juce_getImageContext (image)\r
+ flipped: false]];\r
+ #endif\r
}\r
\r
static void releaseImageAfterDrawing()\r
// the dialog box. This means that the actual native FileChooser HWND may\r
// not have been created yet when the user deletes JUCE's FileChooser class. If this\r
// occurs the Win32NativeFileChooser will still have a reference count of 1 and will\r
-// simply delete itself immedietely once the HWND will have been created a while later.\r
+// simply delete itself immediately once the HWND will have been created a while later.\r
class Win32NativeFileChooser : public ReferenceCountedObject,\r
private Thread\r
{\r
extern void juce_checkCurrentlyFocusedTopLevelWindow(); // in juce_TopLevelWindow.cpp\r
extern bool juce_isRunningInWine();\r
\r
-typedef bool (*CheckEventBlockedByModalComps) (const MSG&);\r
+using CheckEventBlockedByModalComps = bool (*)(const MSG&);\r
extern CheckEventBlockedByModalComps isEventBlockedByModalComps;\r
\r
static bool shouldDeactivateTitleBar = true;\r
#endif\r
\r
//==============================================================================\r
-typedef void (*SettingChangeCallbackFunc) (void);\r
+using SettingChangeCallbackFunc = void (*)(void);\r
extern SettingChangeCallbackFunc settingChangeCallback;\r
\r
//==============================================================================\r
scale = 1.0 / Desktop::getInstance().getDisplays().getMainDisplay().scale;\r
#endif\r
\r
- const RECT r = { roundToInt (area.getX() * scale), roundToInt (area.getY() * scale),\r
- roundToInt (area.getRight() * scale), roundToInt (area.getBottom() * scale) };\r
+ auto scaled = area.toDouble() * scale;\r
+ auto r = RECTFromRectangle (scaled.getSmallestIntegerContainer());\r
\r
InvalidateRect (hwnd, &r, FALSE);\r
}\r
These are the values that will be read and written to the\r
valueToControl value. This array must contain the same number of items\r
as the choices array\r
- @param maxChoices the maxmimum number of values which can be selected at once. The default of\r
+ @param maxChoices the maximum number of values which can be selected at once. The default of\r
-1 will not limit the number that can be selected\r
*/\r
MultiChoicePropertyComponent (const Value& valueToControl,\r
These are the values that will be read and written to the\r
valueToControl value. This array must contain the same number of items\r
as the choices array\r
- @param maxChoices the maxmimum number of values which can be selected at once. The default of\r
+ @param maxChoices the maximum number of values which can be selected at once. The default of\r
-1 will not limit the number that can be selected\r
*/\r
MultiChoicePropertyComponent (ValueWithDefault& valueToControl,\r
The components in the list will be owned by this object and will be automatically\r
deleted later on when no longer needed.\r
\r
- To add properies without them being in a section, use addProperties().\r
+ To add properties without them being in a section, use addProperties().\r
*/\r
void addSection (const String& sectionTitle,\r
const Array<PropertyComponent*>& newPropertyComponents,\r
// you can't add empty strings to the list..\r
jassert (newItemText.isNotEmpty());\r
\r
- // IDs must be non-zero, as zero is used to indicate a lack of selecion.\r
+ // IDs must be non-zero, as zero is used to indicate a lack of selection.\r
jassert (newItemId != 0);\r
\r
// you shouldn't use duplicate item IDs!\r
// showPopup asynchronously, we are giving the other popups a chance to properly\r
// close themselves\r
MessageManager::callAsync ([safePointer]() mutable { if (safePointer != nullptr) safePointer->showPopup(); });\r
+\r
+ repaint();\r
}\r
}\r
\r
\r
The text passed-in will be set as the current text regardless of whether\r
it is one of the items in the list. If the current text isn't one of the\r
- items, then getSelectedId() will return 0, otherwise it wil return\r
- the approriate ID.\r
+ items, then getSelectedId() will return 0, otherwise it will return\r
+ the appropriate ID.\r
\r
@param newText the text to select\r
@param notification determines the type of change notification that will\r
{\r
notDragging, /**< Dragging is not active. */\r
absoluteDrag, /**< The dragging corresponds directly to the value that is displayed. */\r
- velocityDrag /**< The dragging value change is relative to the velocity of the mouse mouvement. */\r
+ velocityDrag /**< The dragging value change is relative to the velocity of the mouse movement. */\r
};\r
\r
//==============================================================================\r
\r
/** Triggers a re-sort of the table according to the current sort-column.\r
\r
- If you modifiy the table's contents, you can call this to signal that the table needs\r
+ If you modify the table's contents, you can call this to signal that the table needs\r
to be re-sorted.\r
\r
(This doesn't do any sorting synchronously - it just asynchronously sends a call to the\r
\r
The index is an index from 0 to the number of columns that are currently visible (hidden\r
ones are not counted). It returns a rectangle showing the position of the column relative\r
- to this component's top-left. If the index is out-of-range, an empty rectangle is retrurned.\r
+ to this component's top-left. If the index is out-of-range, an empty rectangle is returned.\r
*/\r
Rectangle<int> getColumnPosition (int index) const;\r
\r
highlightColourId = 0x1003830, /**< The colour of the table header background when\r
the mouse is over or down above the the table\r
header. It's up to the LookAndFeel to use a\r
- variant of this colour to destiuish between\r
+ variant of this colour to distinguish between\r
the down and hover state. */\r
};\r
\r
/** Returns the index of this item in its parent's sub-items. */\r
int getIndexInParent() const noexcept;\r
\r
- /** Returns true if this item is the last of its parent's sub-itens. */\r
+ /** Returns true if this item is the last of its parent's sub-items. */\r
bool isLastOfSiblings() const noexcept;\r
\r
/** Creates a string that can be used to uniquely retrieve this item in the tree.\r
linesColourId = 0x1000501, /**< The colour to draw the lines with.*/\r
dragAndDropIndicatorColourId = 0x1000502, /**< The colour to use for the drag-and-drop target position indicator. */\r
selectedItemBackgroundColourId = 0x1000503, /**< The colour to use to fill the background of any selected items. */\r
- oddItemsColourId = 0x1000504, /**< The colour to use to fill the backround of the odd numbered items. */\r
- evenItemsColourId = 0x1000505 /**< The colour to use to fill the backround of the even numbered items. */\r
+ oddItemsColourId = 0x1000504, /**< The colour to use to fill the background of the odd numbered items. */\r
+ evenItemsColourId = 0x1000505 /**< The colour to use to fill the background of the even numbered items. */\r
};\r
\r
//==============================================================================\r
for (auto* t : textBoxes)\r
t->setWantsKeyboardFocus (false);\r
\r
- // Giveaway focus before removing the editors, so that any TextEditor\r
+ // Give away focus before removing the editors, so that any TextEditor\r
// with focus has a chance to dismiss native keyboard if shown.\r
if (hasKeyboardFocus (true))\r
Component::unfocusAllComponents();\r
//==============================================================================\r
/** Easy way of quickly showing a dialog box containing a given component.\r
\r
- Note: This method has been superceded by the DialogWindow::LaunchOptions structure,\r
+ Note: This method has been superseded by the DialogWindow::LaunchOptions structure,\r
which does the same job with some extra flexibility. The showDialog method is here\r
for backwards compatibility, but please use DialogWindow::LaunchOptions in new code.\r
\r
#if JUCE_MODAL_LOOPS_PERMITTED || DOXYGEN\r
/** Easy way of quickly showing a dialog box containing a given component.\r
\r
- Note: This method has been superceded by the DialogWindow::LaunchOptions structure,\r
+ Note: This method has been superseded by the DialogWindow::LaunchOptions structure,\r
which does the same job with some extra flexibility. The showDialog method is here\r
for backwards compatibility, but please use DialogWindow::LaunchOptions in new code.\r
\r
A pointer to the object you pass in will be kept, but it won't be deleted\r
by this object, so it's the caller's responsibility to manage it.\r
\r
- If you pass a nullptr, then no contraints will be placed on the positioning of the window.\r
+ If you pass a nullptr, then no constraints will be placed on the positioning of the window.\r
*/\r
void setConstrainer (ComponentBoundsConstrainer* newConstrainer);\r
\r
*/\r
virtual void performPopupMenuAction (int menuItemID);\r
\r
- /** Specifies a commmand-manager which the editor will notify whenever the state\r
+ /** Specifies a command-manager which the editor will notify whenever the state\r
of any of its commands changes.\r
If you're making use of the editor's ApplicationCommandTarget interface, then\r
you should also use this to tell it which command manager it should use. Make\r
when it goes out of scope.\r
\r
If you create one of these before creating a top-level window, the window\r
- will be DPI unaware and bitmap strectched by the OS on a display with >100%\r
+ will be DPI unaware and bitmap stretched by the OS on a display with >100%\r
scaling.\r
\r
You shouldn't use this unless you really know what you are doing and\r
are dealing with native HWNDs.\r
+\r
+ @tags{GUI}\r
*/\r
class JUCE_API ScopedDPIAwarenessDisabler\r
{\r
==============================================================================\r
*/\r
\r
+\r
/*******************************************************************************\r
The block below describes the properties of this module, and is read by\r
the Projucer to automatically generate project code that uses it.\r
\r
BEGIN_JUCE_MODULE_DECLARATION\r
\r
- ID: juce_gui_extra\r
- vendor: juce\r
- version: 5.4.5\r
- name: JUCE extended GUI classes\r
- description: Miscellaneous GUI classes for specialised tasks.\r
- website: http://www.juce.com/juce\r
- license: GPL/Commercial\r
+ ID: juce_gui_extra\r
+ vendor: juce\r
+ version: 5.4.6\r
+ name: JUCE extended GUI classes\r
+ description: Miscellaneous GUI classes for specialised tasks.\r
+ website: http://www.juce.com/juce\r
+ license: GPL/Commercial\r
\r
- dependencies: juce_gui_basics\r
- OSXFrameworks: WebKit\r
+ dependencies: juce_gui_basics\r
+ OSXFrameworks: WebKit\r
\r
END_JUCE_MODULE_DECLARATION\r
\r
@param position the coords of the object to point to\r
@param message the text to display\r
@param numMillisecondsBeforeRemoving how long to leave it on the screen before removing itself\r
- from its parent compnent. If this is 0 or less, it\r
+ from its parent component. If this is 0 or less, it\r
will stay there until manually removed.\r
@param removeWhenMouseClicked if this is true, the bubble will disappear as soon as a\r
mouse button is pressed (anywhere on the screen)\r
@param component the component that you want to point at\r
@param message the text to display\r
@param numMillisecondsBeforeRemoving how long to leave it on the screen before removing itself\r
- from its parent compnent. If this is 0 or less, it\r
+ from its parent component. If this is 0 or less, it\r
will stay there until manually removed.\r
@param removeWhenMouseClicked if this is true, the bubble will disappear as soon as a\r
mouse button is pressed (anywhere on the screen)\r
JUCE_DECLARE_NON_COPYABLE (SwatchComponent)\r
};\r
\r
+//==============================================================================\r
+class ColourSelector::ColourPreviewComp : public Component\r
+{\r
+public:\r
+ ColourPreviewComp (ColourSelector& cs, bool isEditable)\r
+ : owner (cs)\r
+ {\r
+ colourLabel.setFont (labelFont);\r
+ colourLabel.setJustificationType (Justification::centred);\r
+\r
+ if (isEditable)\r
+ {\r
+ colourLabel.setEditable (true);\r
+\r
+ colourLabel.onEditorShow = [this]\r
+ {\r
+ if (auto* ed = colourLabel.getCurrentTextEditor())\r
+ ed->setInputRestrictions ((owner.flags & showAlphaChannel) ? 8 : 6, "1234567890ABCDEFabcdef");\r
+ };\r
+\r
+ colourLabel.onEditorHide = [this]\r
+ {\r
+ updateColourIfNecessary (colourLabel.getText());\r
+ };\r
+ }\r
+\r
+ addAndMakeVisible (colourLabel);\r
+ }\r
+\r
+ void updateIfNeeded()\r
+ {\r
+ auto newColour = owner.getCurrentColour();\r
+\r
+ if (currentColour != newColour)\r
+ {\r
+ currentColour = newColour;\r
+ auto textColour = (Colours::white.overlaidWith (currentColour).contrasting());\r
+\r
+ colourLabel.setColour (Label::textColourId, textColour);\r
+ colourLabel.setColour (Label::textWhenEditingColourId, textColour);\r
+ colourLabel.setText (currentColour.toDisplayString ((owner.flags & showAlphaChannel) != 0), dontSendNotification);\r
+\r
+ labelWidth = labelFont.getStringWidth (colourLabel.getText());\r
+\r
+ repaint();\r
+ }\r
+ }\r
+\r
+ void paint (Graphics& g) override\r
+ {\r
+ g.fillCheckerBoard (getLocalBounds().toFloat(), 10.0f, 10.0f,\r
+ Colour (0xffdddddd).overlaidWith (currentColour),\r
+ Colour (0xffffffff).overlaidWith (currentColour));\r
+ }\r
+\r
+ void resized() override\r
+ {\r
+ colourLabel.centreWithSize (labelWidth + 10, (int) labelFont.getHeight() + 10);\r
+ }\r
+\r
+private:\r
+ void updateColourIfNecessary (const String& newColourString)\r
+ {\r
+ auto newColour = Colour::fromString (newColourString);\r
+\r
+ if (newColour != currentColour)\r
+ owner.setCurrentColour (newColour);\r
+ }\r
+\r
+ ColourSelector& owner;\r
+\r
+ Colour currentColour;\r
+ Font labelFont { 14.0f, Font::bold };\r
+ int labelWidth = 0;\r
+ Label colourLabel;\r
+\r
+ JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ColourPreviewComp)\r
+};\r
+\r
//==============================================================================\r
ColourSelector::ColourSelector (int sectionsToShow, int edge, int gapAroundColourSpaceComponent)\r
: colour (Colours::white),\r
\r
updateHSV();\r
\r
+ if ((flags & showColourAtTop) != 0)\r
+ {\r
+ previewComponent.reset (new ColourPreviewComp (*this, (flags & editableColour) != 0));\r
+ addAndMakeVisible (previewComponent.get());\r
+ }\r
+\r
if ((flags & showSliders) != 0)\r
{\r
sliders[0].reset (new ColourComponentSlider (TRANS ("red")));\r
hueSelector->updateIfNeeded();\r
}\r
\r
- if ((flags & showColourAtTop) != 0)\r
- repaint (previewArea);\r
+ if (previewComponent != nullptr)\r
+ previewComponent->updateIfNeeded();\r
\r
if (notification != dontSendNotification)\r
sendChangeMessage();\r
{\r
g.fillAll (findColour (backgroundColourId));\r
\r
- if ((flags & showColourAtTop) != 0)\r
- {\r
- auto currentColour = getCurrentColour();\r
-\r
- g.fillCheckerBoard (previewArea.toFloat(), 10.0f, 10.0f,\r
- Colour (0xffdddddd).overlaidWith (currentColour),\r
- Colour (0xffffffff).overlaidWith (currentColour));\r
-\r
- g.setColour (Colours::white.overlaidWith (currentColour).contrasting());\r
- g.setFont (Font (14.0f, Font::bold));\r
- g.drawText (currentColour.toDisplayString ((flags & showAlphaChannel) != 0),\r
- previewArea, Justification::centred, false);\r
- }\r
-\r
if ((flags & showSliders) != 0)\r
{\r
g.setColour (findColour (labelTextColourId));\r
const int sliderSpace = ((flags & showSliders) != 0) ? jmin (22 * numSliders + edgeGap, proportionOfHeight (0.3f)) : 0;\r
const int topSpace = ((flags & showColourAtTop) != 0) ? jmin (30 + edgeGap * 2, proportionOfHeight (0.2f)) : edgeGap;\r
\r
- previewArea.setBounds (edgeGap, edgeGap, getWidth() - edgeGap * 2, topSpace - edgeGap * 2);\r
+ if (previewComponent != nullptr)\r
+ previewComponent->setBounds (edgeGap, edgeGap, getWidth() - edgeGap * 2, topSpace - edgeGap * 2);\r
\r
int y = topSpace;\r
\r
showAlphaChannel = 1 << 0, /**< if set, the colour's alpha channel can be changed as well as its RGB. */\r
\r
showColourAtTop = 1 << 1, /**< if set, a swatch of the colour is shown at the top of the component. */\r
- showSliders = 1 << 2, /**< if set, RGB sliders are shown at the bottom of the component. */\r
- showColourspace = 1 << 3 /**< if set, a big HSV selector is shown. */\r
+ editableColour = 1 << 2, /**< if set, the colour shows at the top of the component is editable. */\r
+ showSliders = 1 << 3, /**< if set, RGB sliders are shown at the bottom of the component. */\r
+ showColourspace = 1 << 4 /**< if set, a big HSV selector is shown. */\r
};\r
\r
//==============================================================================\r
// These need to be public otherwise the Projucer's live-build engine will complain\r
class ColourSpaceView;\r
class HueSelectorComp;\r
+ class ColourPreviewComp;\r
\r
private:\r
//==============================================================================\r
std::unique_ptr<Slider> sliders[4];\r
std::unique_ptr<ColourSpaceView> colourSpace;\r
std::unique_ptr<HueSelectorComp> hueSelector;\r
+ std::unique_ptr<ColourPreviewComp> previewComponent;\r
OwnedArray<SwatchComponent> swatchComponents;\r
const int flags;\r
int edgeGap;\r
- Rectangle<int> previewArea;\r
\r
void setHue (float newH);\r
void setSV (float newS, float newV);\r
bool localOnly = true; /**< Optional: whether or not the notification should bridge to other devices.\r
Available from Android API 20 or above. */\r
\r
- bool ongoing = false; /**< Optional: If true, then it cannot be dismissed by the user and it must be dimissed manually.\r
+ bool ongoing = false; /**< Optional: If true, then it cannot be dismissed by the user and it must be dismissed manually.\r
Typically used for ongoing background tasks that the user is actively engaged with. To\r
dismiss such notification, you need to call removeDeliveredNotification() or\r
removeAllDeliveredNotifications(). */\r
{\r
using Action = Notification::Action;\r
\r
- /** Describes a category of a notification. Each category has a unique idenfifier\r
+ /** Describes a category of a notification. Each category has a unique identifier\r
and a list of associated actions.\r
Note that the OS may allow only a limited number of actions to be presented, so\r
always present most important actions first.\r
\r
@param isLocalNotification If the notification is local\r
@param notification The notification\r
- @param actionIdentifier A String identifiing the action\r
+ @param actionIdentifier A String identifying the action\r
@param optionalResponse Text response a user inputs for notifications with a text input.\r
Empty for notifications without a text input option.\r
\r
auto classAsString = LocalRef<jstring> ((jstring) env->CallObjectMethod (objectClass, JavaClass.getName));\r
\r
// Note: It seems that Firebase delivers values as strings always, so this check is rather unnecessary,\r
- // at least untill they change the behaviour.\r
+ // at least until they change the behaviour.\r
var value = juceString (classAsString) == "java.lang.Bundle" ? bundleToVar (object) : var (juceString (objectAsString.get()));\r
dynamicObject->setProperty (juceString (key.get()), value);\r
}\r
propertiesDynamicObject->setProperty ("titleLocalizationKey", juceString (titleLocalizationKey.get()));\r
propertiesDynamicObject->setProperty ("bodyLocalizationArgs", javaStringArrayToJuce (bodyLocalizationArgs));\r
propertiesDynamicObject->setProperty ("titleLocalizationArgs", javaStringArrayToJuce (titleLocalizationArgs));\r
- propertiesDynamicObject->setProperty ("link", link.get() == nullptr ? juceString ((jstring) env->CallObjectMethod (link, AndroidUri.toString)) : String());\r
+ propertiesDynamicObject->setProperty ("link", link.get() != nullptr ? juceString ((jstring) env->CallObjectMethod (link, AndroidUri.toString)) : String());\r
}\r
\r
n.properties = var (propertiesDynamicObject.get());\r
DECLARE_JNI_CLASS (InstanceIdService, "com/roli/juce/JuceFirebaseInstanceIdService")\r
#undef JNI_CLASS_MEMBERS\r
\r
- static void JNICALL tokenRefreshed (void* token)\r
+ static void JNICALL tokenRefreshed (JNIEnv*, jobject /*instanceIdService*/, void* token)\r
{\r
if (auto* instance = PushNotifications::getInstanceWithoutCreating())\r
instance->pimpl->notifyListenersTokenRefreshed (juceString (static_cast<jstring> (token)));\r
{\r
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \\r
CALLBACK (remoteNotificationReceived, "firebaseRemoteMessageReceived", "(Lcom/google/firebase/messaging/RemoteMessage;)V") \\r
- CALLBACK (remoteMessagesDeleted, "firebaseRemoteMessagesDeleted", "()V") \\r
- CALLBACK (remoteMessageSent, "firebaseRemoteMessageSent", "(Ljava/lang/String;)V") \\r
- CALLBACK (remoteMessageSendError, "firebaseRemoteMessageSendError", "(Ljava/lang/String;Ljava/lang/String;)V")\r
+ CALLBACK (remoteMessagesDeleted, "firebaseRemoteMessagesDeleted", "()V") \\r
+ CALLBACK (remoteMessageSent, "firebaseRemoteMessageSent", "(Ljava/lang/String;)V") \\r
+ CALLBACK (remoteMessageSendError, "firebaseRemoteMessageSendError", "(Ljava/lang/String;Ljava/lang/String;)V")\r
\r
DECLARE_JNI_CLASS (MessagingService, "com/roli/juce/JuceFirebaseMessagingService")\r
#undef JNI_CLASS_MEMBERS\r
}\r
\r
// request\r
- // each notification on iOS 10 needs to have an identifer, otherwise it will not show up\r
+ // each notification on iOS 10 needs to have an identifier, otherwise it will not show up\r
jassert (n.identifier.isNotEmpty());\r
UNNotificationRequest* request = [UNNotificationRequest requestWithIdentifier: juceStringToNS (n.identifier)\r
content: content\r
if (n.fireDate != nil)\r
{\r
NSDate* dateNow = [NSDate date];\r
- notif.triggerIntervalSec = [dateNow timeIntervalSinceDate: n.fireDate];\r
+ NSDate* fireDate = n.fireDate;\r
+\r
+ notif.triggerIntervalSec = [dateNow timeIntervalSinceDate: fireDate];\r
}\r
\r
notif.soundToPlay = URL (nsStringToJuce (n.soundName));\r
\r
void registeredForRemoteNotifications (NSData* deviceTokenToUse) override\r
{\r
- NSString* deviceTokenString = [[[[deviceTokenToUse description]\r
- stringByReplacingOccurrencesOfString: nsStringLiteral ("<") withString: nsStringLiteral ("")]\r
- stringByReplacingOccurrencesOfString: nsStringLiteral (">") withString: nsStringLiteral ("")]\r
- stringByReplacingOccurrencesOfString: nsStringLiteral (" ") withString: nsStringLiteral ("")];\r
+ deviceToken = [deviceTokenToUse]() -> String\r
+ {\r
+ auto length = deviceTokenToUse.length;\r
+\r
+ if (auto* buffer = (const unsigned char*) deviceTokenToUse.bytes)\r
+ {\r
+ NSMutableString* hexString = [NSMutableString stringWithCapacity: (length * 2)];\r
\r
- deviceToken = nsStringToJuce (deviceTokenString);\r
+ for (NSUInteger i = 0; i < length; ++i)\r
+ [hexString appendFormat:@"%02x", buffer[i]];\r
+\r
+ return nsStringToJuce ([hexString copy]);\r
+ }\r
+\r
+ return {};\r
+ }();\r
\r
initialised = true;\r
\r
else\r
{\r
NSDate* dateNow = [NSDate date];\r
- notif.triggerIntervalSec = [dateNow timeIntervalSinceDate: n.deliveryDate];\r
+ NSDate* deliveryDate = n.deliveryDate;\r
+\r
+ notif.triggerIntervalSec = [dateNow timeIntervalSinceDate: deliveryDate];\r
}\r
\r
notif.soundToPlay = URL (nsStringToJuce (n.soundName));\r
NSRemoteNotificationType types = NSUInteger ((bool) settings.allowBadge);\r
\r
if (isAtLeastMountainLion)\r
- types |= ((bool) settings.allowSound << 1 | (bool) settings.allowAlert << 2);\r
+ types |= (NSUInteger) ((bool) settings.allowSound << 1 | (bool) settings.allowAlert << 2);\r
\r
[[NSApplication sharedApplication] registerForRemoteNotificationTypes: types];\r
}\r
//PushNotificationsDelegate\r
void registeredForRemoteNotifications (NSData* deviceTokenToUse) override\r
{\r
- auto deviceTokenString = [[[[deviceTokenToUse description]\r
- stringByReplacingOccurrencesOfString: nsStringLiteral ("<") withString: nsStringLiteral ("")]\r
- stringByReplacingOccurrencesOfString: nsStringLiteral (">") withString: nsStringLiteral ("")]\r
- stringByReplacingOccurrencesOfString: nsStringLiteral (" ") withString: nsStringLiteral ("")];\r
+ deviceToken = [deviceTokenToUse]() -> String\r
+ {\r
+ auto length = deviceTokenToUse.length;\r
+\r
+ if (auto* buffer = (const unsigned char*) deviceTokenToUse.bytes)\r
+ {\r
+ NSMutableString* hexString = [NSMutableString stringWithCapacity: (length * 2)];\r
\r
- deviceToken = nsStringToJuce (deviceTokenString);\r
+ for (NSUInteger i = 0; i < length; ++i)\r
+ [hexString appendFormat:@"%02x", buffer[i]];\r
+\r
+ return nsStringToJuce ([hexString copy]);\r
+ }\r
+\r
+ return {};\r
+ }();\r
\r
initialised = true;\r
\r
}\r
}\r
\r
- bool shouldPresentNotification (NSUserNotification* notification) override { return true; }\r
+ bool shouldPresentNotification (NSUserNotification*) override { return true; }\r
\r
void subscribeToTopic (const String& topic) { ignoreUnused (topic); }\r
void unsubscribeFromTopic (const String& topic) { ignoreUnused (topic); }\r
namespace juce\r
{\r
\r
+#pragma clang diagnostic push\r
+#pragma clang diagnostic ignored "-Wunguarded-availability"\r
+#if JUCE_CLANG && defined (MAC_OS_X_VERSION_10_14) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_14\r
+ #pragma clang diagnostic ignored "-Wdeprecated-declarations"\r
+#endif\r
+\r
extern NSMenu* createNSMenu (const PopupMenu&, const String& name, int topLevelMenuId,\r
int topLevelIndex, bool addDelegate);\r
\r
-class SystemTrayIconComponent::Pimpl : private Timer\r
+//==============================================================================\r
+struct StatusItemContainer : public Timer\r
{\r
-public:\r
//==============================================================================\r
- Pimpl (SystemTrayIconComponent& iconComp, const Image& im)\r
+ StatusItemContainer (SystemTrayIconComponent& iconComp, const Image& im)\r
: owner (iconComp), statusIcon (imageToNSImage (im))\r
{\r
- static ButtonEventForwarderClass cls;\r
- eventForwarder.reset ([cls.createInstance() init]);\r
- ButtonEventForwarderClass::setOwner (eventForwarder.get(), this);\r
+ }\r
\r
- configureIcon();\r
+ virtual void configureIcon() = 0;\r
+ virtual void setHighlighted (bool shouldHighlight) = 0;\r
\r
- statusItem.reset ([[[NSStatusBar systemStatusBar] statusItemWithLength: NSSquareStatusItemLength] retain]);\r
- auto button = [statusItem.get() button];\r
- button.image = statusIcon.get();\r
- button.target = eventForwarder.get();\r
- button.action = @selector (handleEvent:);\r
- #if defined (MAC_OS_X_VERSION_10_12) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_12\r
- [button sendActionOn: NSEventMaskLeftMouseDown | NSEventMaskRightMouseDown | NSEventMaskScrollWheel];\r
- #else\r
- [button sendActionOn: NSLeftMouseDownMask | NSRightMouseDownMask | NSScrollWheelMask];\r
- #endif\r
+ //==============================================================================\r
+ void setIconSize()\r
+ {\r
+ [statusIcon.get() setSize: NSMakeSize (20.0f, 20.0f)];\r
}\r
\r
- //==============================================================================\r
void updateIcon (const Image& newImage)\r
{\r
statusIcon.reset (imageToNSImage (newImage));\r
+ setIconSize();\r
configureIcon();\r
- [statusItem.get() button].image = statusIcon.get();\r
- }\r
-\r
- void setHighlighted (bool shouldHighlight)\r
- {\r
- [[statusItem.get() button] setHighlighted: shouldHighlight];\r
}\r
\r
void showMenu (const PopupMenu& menu)\r
setHighlighted (true);\r
stopTimer();\r
\r
- // There's currently no good alternative to this...\r
- #if JUCE_CLANG && ! (defined (MAC_OS_X_VERSION_10_16) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_16)\r
- #pragma clang diagnostic push\r
- #pragma clang diagnostic ignored "-Wdeprecated-declarations"\r
- #define JUCE_DEPRECATION_IGNORED 1\r
- #endif\r
-\r
+ // There's currently no good alternative to this.\r
[statusItem.get() popUpStatusItemMenu: m];\r
\r
- #if JUCE_DEPRECATION_IGNORED\r
- #pragma clang diagnostic pop\r
- #undef JUCE_DEPRECATION_IGNORED\r
- #endif\r
-\r
startTimer (1);\r
}\r
}\r
\r
//==============================================================================\r
- NSStatusItem* getStatusItem()\r
+ void timerCallback() override\r
+ {\r
+ stopTimer();\r
+ setHighlighted (false);\r
+ }\r
+\r
+ //==============================================================================\r
+ SystemTrayIconComponent& owner;\r
+\r
+ std::unique_ptr<NSStatusItem, NSObjectDeleter> statusItem;\r
+ std::unique_ptr<NSImage, NSObjectDeleter> statusIcon;\r
+\r
+ JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (StatusItemContainer)\r
+};\r
+\r
+//==============================================================================\r
+struct ButtonBasedStatusItem : public StatusItemContainer\r
+{\r
+ //==============================================================================\r
+ ButtonBasedStatusItem (SystemTrayIconComponent& iconComp, const Image& im)\r
+ : StatusItemContainer (iconComp, im)\r
+ {\r
+ static ButtonEventForwarderClass cls;\r
+ eventForwarder.reset ([cls.createInstance() init]);\r
+ ButtonEventForwarderClass::setOwner (eventForwarder.get(), this);\r
+\r
+ setIconSize();\r
+ configureIcon();\r
+\r
+ statusItem.reset ([[[NSStatusBar systemStatusBar] statusItemWithLength: NSSquareStatusItemLength] retain]);\r
+ auto button = [statusItem.get() button];\r
+ button.image = statusIcon.get();\r
+ button.target = eventForwarder.get();\r
+ button.action = @selector (handleEvent:);\r
+ #if defined (MAC_OS_X_VERSION_10_12) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_12\r
+ [button sendActionOn: NSEventMaskLeftMouseDown | NSEventMaskRightMouseDown | NSEventMaskScrollWheel];\r
+ #else\r
+ [button sendActionOn: NSLeftMouseDownMask | NSRightMouseDownMask | NSScrollWheelMask];\r
+ #endif\r
+ }\r
+\r
+ void configureIcon() override\r
{\r
- return statusItem.get();\r
+ [statusIcon.get() setTemplate: true];\r
+ [statusItem.get() button].image = statusIcon.get();\r
+ }\r
+\r
+ void setHighlighted (bool shouldHighlight) override\r
+ {\r
+ [[statusItem.get() button] setHighlighted: shouldHighlight];\r
}\r
\r
//==============================================================================\r
}\r
}\r
\r
-private:\r
- //==============================================================================\r
- void configureIcon()\r
- {\r
- [statusIcon.get() setSize: NSMakeSize (20.0f, 20.0f)];\r
- [statusIcon.get() setTemplate: true];\r
- }\r
-\r
- void timerCallback() override\r
- {\r
- stopTimer();\r
- setHighlighted (false);\r
- }\r
-\r
//==============================================================================\r
class ButtonEventForwarderClass : public ObjCClass<NSObject>\r
{\r
public:\r
ButtonEventForwarderClass() : ObjCClass<NSObject> ("JUCEButtonEventForwarderClass_")\r
{\r
- addIvar<Pimpl*> ("owner");\r
+ addIvar<ButtonBasedStatusItem*> ("owner");\r
\r
addMethod (@selector (handleEvent:), handleEvent, "v@:@");\r
\r
registerClass();\r
}\r
\r
- static Pimpl* getOwner (id self) { return getIvar<Pimpl*> (self, "owner"); }\r
- static void setOwner (id self, Pimpl* owner) { object_setInstanceVariable (self, "owner", owner); }\r
+ static ButtonBasedStatusItem* getOwner (id self) { return getIvar<ButtonBasedStatusItem*> (self, "owner"); }\r
+ static void setOwner (id self, ButtonBasedStatusItem* owner) { object_setInstanceVariable (self, "owner", owner); }\r
\r
private:\r
static void handleEvent (id self, SEL, id)\r
};\r
\r
//==============================================================================\r
- SystemTrayIconComponent& owner;\r
- std::unique_ptr<NSStatusItem, NSObjectDeleter> statusItem;\r
std::unique_ptr<NSObject, NSObjectDeleter> eventForwarder;\r
- std::unique_ptr<NSImage, NSObjectDeleter> statusIcon;\r
+};\r
\r
- JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Pimpl)\r
+//==============================================================================\r
+struct ViewBasedStatusItem : public StatusItemContainer\r
+{\r
+ //==============================================================================\r
+ ViewBasedStatusItem (SystemTrayIconComponent& iconComp, const Image& im)\r
+ : StatusItemContainer (iconComp, im)\r
+ {\r
+ static SystemTrayViewClass cls;\r
+ view.reset ([cls.createInstance() init]);\r
+ SystemTrayViewClass::setOwner (view.get(), this);\r
+ SystemTrayViewClass::setImage (view.get(), statusIcon.get());\r
+\r
+ setIconSize();\r
+\r
+ statusItem.reset ([[[NSStatusBar systemStatusBar] statusItemWithLength: NSSquareStatusItemLength] retain]);\r
+ [statusItem.get() setView: view.get()];\r
+\r
+ SystemTrayViewClass::frameChanged (view.get(), SEL(), nullptr);\r
+\r
+ [[NSNotificationCenter defaultCenter] addObserver: view.get()\r
+ selector: @selector (frameChanged:)\r
+ name: NSWindowDidMoveNotification\r
+ object: nil];\r
+ }\r
+\r
+ ~ViewBasedStatusItem() override\r
+ {\r
+ [[NSNotificationCenter defaultCenter] removeObserver: view.get()];\r
+ [[NSStatusBar systemStatusBar] removeStatusItem: statusItem.get()];\r
+ SystemTrayViewClass::setOwner (view.get(), nullptr);\r
+ SystemTrayViewClass::setImage (view.get(), nil);\r
+ }\r
+\r
+ void configureIcon() override\r
+ {\r
+ SystemTrayViewClass::setImage (view.get(), statusIcon.get());\r
+ [statusItem.get() setView: view.get()];\r
+ }\r
+\r
+ void setHighlighted (bool shouldHighlight) override\r
+ {\r
+ isHighlighted = shouldHighlight;\r
+ [view.get() setNeedsDisplay: true];\r
+ }\r
+\r
+ //==============================================================================\r
+ void handleStatusItemAction (NSEvent* e)\r
+ {\r
+ NSEventType type = [e type];\r
+\r
+ const bool isLeft = (type == NSEventTypeLeftMouseDown || type == NSEventTypeLeftMouseUp);\r
+ const bool isRight = (type == NSEventTypeRightMouseDown || type == NSEventTypeRightMouseUp);\r
+\r
+ if (owner.isCurrentlyBlockedByAnotherModalComponent())\r
+ {\r
+ if (isLeft || isRight)\r
+ if (auto* current = Component::getCurrentlyModalComponent())\r
+ current->inputAttemptWhenModal();\r
+ }\r
+ else\r
+ {\r
+ auto eventMods = ComponentPeer::getCurrentModifiersRealtime();\r
+\r
+ if (([e modifierFlags] & NSEventModifierFlagCommand) != 0)\r
+ eventMods = eventMods.withFlags (ModifierKeys::commandModifier);\r
+\r
+ auto now = Time::getCurrentTime();\r
+ auto mouseSource = Desktop::getInstance().getMainMouseSource();\r
+ auto pressure = (float) e.pressure;\r
+\r
+ if (isLeft || isRight) // Only mouse up is sent by the OS, so simulate a down/up\r
+ {\r
+ setHighlighted (true);\r
+ startTimer (150);\r
+\r
+ owner.mouseDown (MouseEvent (mouseSource, {},\r
+ eventMods.withFlags (isLeft ? ModifierKeys::leftButtonModifier\r
+ : ModifierKeys::rightButtonModifier),\r
+ pressure, MouseInputSource::invalidOrientation, MouseInputSource::invalidRotation,\r
+ MouseInputSource::invalidTiltX, MouseInputSource::invalidTiltY,\r
+ &owner, &owner, now, {}, now, 1, false));\r
+\r
+ owner.mouseUp (MouseEvent (mouseSource, {}, eventMods.withoutMouseButtons(), pressure,\r
+ MouseInputSource::invalidOrientation, MouseInputSource::invalidRotation,\r
+ MouseInputSource::invalidTiltX, MouseInputSource::invalidTiltY,\r
+ &owner, &owner, now, {}, now, 1, false));\r
+ }\r
+ else if (type == NSEventTypeMouseMoved)\r
+ {\r
+ owner.mouseMove (MouseEvent (mouseSource, {}, eventMods, pressure,\r
+ MouseInputSource::invalidOrientation, MouseInputSource::invalidRotation,\r
+ MouseInputSource::invalidTiltX, MouseInputSource::invalidTiltY,\r
+ &owner, &owner, now, {}, now, 1, false));\r
+ }\r
+ }\r
+ }\r
+\r
+ //==============================================================================\r
+ struct SystemTrayViewClass : public ObjCClass<NSControl>\r
+ {\r
+ SystemTrayViewClass() : ObjCClass<NSControl> ("JUCESystemTrayView_")\r
+ {\r
+ addIvar<ViewBasedStatusItem*> ("owner");\r
+ addIvar<NSImage*> ("image");\r
+\r
+ addMethod (@selector (mouseDown:), handleEventDown, "v@:@");\r
+ addMethod (@selector (rightMouseDown:), handleEventDown, "v@:@");\r
+ addMethod (@selector (drawRect:), drawRect, "v@:@");\r
+ addMethod (@selector (frameChanged:), frameChanged, "v@:@");\r
+\r
+ registerClass();\r
+ }\r
+\r
+ static ViewBasedStatusItem* getOwner (id self) { return getIvar<ViewBasedStatusItem*> (self, "owner"); }\r
+ static NSImage* getImage (id self) { return getIvar<NSImage*> (self, "image"); }\r
+ static void setOwner (id self, ViewBasedStatusItem* owner) { object_setInstanceVariable (self, "owner", owner); }\r
+ static void setImage (id self, NSImage* image) { object_setInstanceVariable (self, "image", image); }\r
+\r
+ static void frameChanged (id self, SEL, NSNotification*)\r
+ {\r
+ if (auto* owner = getOwner (self))\r
+ {\r
+ NSRect r = [[[owner->statusItem.get() view] window] frame];\r
+ NSRect sr = [[[NSScreen screens] objectAtIndex: 0] frame];\r
+ r.origin.y = sr.size.height - r.origin.y - r.size.height;\r
+ owner->owner.setBounds (convertToRectInt (r));\r
+ }\r
+ }\r
+\r
+ private:\r
+ static void handleEventDown (id self, SEL, NSEvent* e)\r
+ {\r
+ if (auto* owner = getOwner (self))\r
+ owner->handleStatusItemAction (e);\r
+ }\r
+\r
+ static void drawRect (id self, SEL, NSRect)\r
+ {\r
+ NSRect bounds = [self bounds];\r
+\r
+ if (auto* owner = getOwner (self))\r
+ [owner->statusItem.get() drawStatusBarBackgroundInRect: bounds\r
+ withHighlight: owner->isHighlighted];\r
+\r
+ if (NSImage* const im = getImage (self))\r
+ {\r
+ NSSize imageSize = [im size];\r
+\r
+ [im drawInRect: NSMakeRect (bounds.origin.x + ((bounds.size.width - imageSize.width) / 2.0f),\r
+ bounds.origin.y + ((bounds.size.height - imageSize.height) / 2.0f),\r
+ imageSize.width, imageSize.height)\r
+ fromRect: NSZeroRect\r
+ operation: NSCompositingOperationSourceOver\r
+ fraction: 1.0f];\r
+ }\r
+ }\r
+ };\r
+\r
+ //==============================================================================\r
+ std::unique_ptr<NSControl, NSObjectDeleter> view;\r
+ bool isHighlighted = false;\r
};\r
\r
+//==============================================================================\r
+class SystemTrayIconComponent::Pimpl\r
+{\r
+public:\r
+ //==============================================================================\r
+ Pimpl (SystemTrayIconComponent& iconComp, const Image& im)\r
+ {\r
+ if (std::floor (NSFoundationVersionNumber) > NSFoundationVersionNumber10_10)\r
+ statusItemHolder = std::make_unique<ButtonBasedStatusItem> (iconComp, im);\r
+ else\r
+ statusItemHolder = std::make_unique<ViewBasedStatusItem> (iconComp, im);\r
+ }\r
+\r
+ //==============================================================================\r
+ std::unique_ptr<StatusItemContainer> statusItemHolder;\r
+\r
+ JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Pimpl)\r
+};\r
\r
//==============================================================================\r
void SystemTrayIconComponent::setIconImage (const Image&, const Image& templateImage)\r
if (pimpl == nullptr)\r
pimpl.reset (new Pimpl (*this, templateImage));\r
else\r
- pimpl->updateIcon (templateImage);\r
+ pimpl->statusItemHolder->updateIcon (templateImage);\r
}\r
else\r
{\r
// xxx not yet implemented!\r
}\r
\r
-void SystemTrayIconComponent::setHighlighted (bool highlight)\r
+void SystemTrayIconComponent::setHighlighted (bool shouldHighlight)\r
{\r
if (pimpl != nullptr)\r
- pimpl->setHighlighted (highlight);\r
+ pimpl->statusItemHolder->setHighlighted (shouldHighlight);\r
}\r
\r
void SystemTrayIconComponent::showInfoBubble (const String& /*title*/, const String& /*content*/)\r
\r
void* SystemTrayIconComponent::getNativeHandle() const\r
{\r
- return pimpl != nullptr ? pimpl->getStatusItem() : nullptr;\r
+ return pimpl != nullptr ? pimpl->statusItemHolder->statusItem.get() : nullptr;\r
}\r
\r
void SystemTrayIconComponent::showDropdownMenu (const PopupMenu& menu)\r
{\r
if (pimpl != nullptr)\r
- pimpl->showMenu (menu);\r
+ pimpl->statusItemHolder->showMenu (menu);\r
}\r
\r
+#pragma clang diagnostic pop\r
+\r
} // namespace juce\r
{\r
if (browser != nullptr)\r
{\r
- LPSAFEARRAY sa = nullptr;\r
-\r
VARIANT headerFlags, frame, postDataVar, headersVar; // (_variant_t isn't available in all compilers)\r
VariantInit (&headerFlags);\r
VariantInit (&frame);\r
\r
if (postData != nullptr && postData->getSize() > 0)\r
{\r
- sa = SafeArrayCreateVector (VT_UI1, 0, (ULONG) postData->getSize());\r
+ auto sa = SafeArrayCreateVector (VT_UI1, 0, (ULONG) postData->getSize());\r
\r
if (sa != nullptr)\r
{\r
V_VT (&postDataVar2) = VT_ARRAY | VT_UI1;\r
V_ARRAY (&postDataVar2) = sa;\r
\r
+ sa = nullptr;\r
postDataVar = postDataVar2;\r
}\r
+ else\r
+ {\r
+ SafeArrayDestroy (sa);\r
+ }\r
}\r
}\r
\r
browser->Navigate (urlBSTR, &headerFlags, &frame, &postDataVar, &headersVar);\r
SysFreeString (urlBSTR);\r
\r
- if (sa != nullptr)\r
- SafeArrayDestroy (sa);\r
-\r
VariantClear (&headerFlags);\r
VariantClear (&frame);\r
VariantClear (&postDataVar);\r
*pDispParams->rgvarg[0].pboolVal = VARIANT_FALSE;\r
\r
// IWebBrowser2 also reports http status codes here, we need\r
- // report only network erros\r
+ // report only network errors\r
if (statusCode < 0)\r
{\r
LPTSTR messageBuffer = nullptr;\r
==============================================================================\r
*/\r
\r
+\r
/*******************************************************************************\r
The block below describes the properties of this module, and is read by\r
the Projucer to automatically generate project code that uses it.\r
\r
BEGIN_JUCE_MODULE_DECLARATION\r
\r
- ID: juce_opengl\r
- vendor: juce\r
- version: 5.4.5\r
- name: JUCE OpenGL classes\r
- description: Classes for rendering OpenGL in a JUCE window.\r
- website: http://www.juce.com/juce\r
- license: GPL/Commercial\r
-\r
- dependencies: juce_gui_extra\r
- OSXFrameworks: OpenGL\r
- iOSFrameworks: OpenGLES\r
- linuxLibs: GL\r
- mingwLibs: opengl32\r
+ ID: juce_opengl\r
+ vendor: juce\r
+ version: 5.4.6\r
+ name: JUCE OpenGL classes\r
+ description: Classes for rendering OpenGL in a JUCE window.\r
+ website: http://www.juce.com/juce\r
+ license: GPL/Commercial\r
+\r
+ dependencies: juce_gui_extra\r
+ OSXFrameworks: OpenGL\r
+ iOSFrameworks: OpenGLES\r
+ linuxLibs: GL\r
+ mingwLibs: opengl32\r
\r
END_JUCE_MODULE_DECLARATION\r
\r
if (context != nil)\r
{\r
// I'd prefer to put this stuff in the initialiseOnRenderThread() call, but doing\r
- // so causes myserious timing-related failures.\r
+ // so causes mysterious timing-related failures.\r
[EAGLContext setCurrentContext: context];\r
createGLBuffers();\r
deactivateCurrentContext();\r
if (renderThread != nullptr)\r
{\r
// make sure everything has finished executing\r
- destroying.set (1);\r
+ destroying = true;\r
\r
if (workQueue.size() > 0)\r
{\r
renderThread->addJob (this, false);\r
}\r
\r
+ #if JUCE_MAC\r
+ static CVReturn displayLinkCallback (CVDisplayLinkRef, const CVTimeStamp*, const CVTimeStamp*,\r
+ CVOptionFlags, CVOptionFlags*, void* displayLinkContext)\r
+ {\r
+ auto* self = (CachedImage*) displayLinkContext;\r
+ self->renderFrame();\r
+ return kCVReturnSuccess;\r
+ }\r
+ #endif\r
+\r
//==============================================================================\r
void paint (Graphics&) override\r
{\r
bool renderFrame()\r
{\r
MessageManager::Lock::ScopedTryLockType mmLock (messageManagerLock, false);\r
- const bool isUpdating = needsUpdate.compareAndSetBool (0, 1);\r
+\r
+ auto isUpdatingTestValue = true;\r
+ auto isUpdating = needsUpdate.compare_exchange_strong (isUpdatingTestValue, false);\r
\r
if (context.renderComponents && isUpdating)\r
{\r
if (shouldExit())\r
break;\r
\r
+ #if JUCE_MAC\r
+ repaintEvent.wait (1000);\r
+ #else\r
if (! renderFrame())\r
repaintEvent.wait (5); // failed to render, so avoid a tight fail-loop.\r
else if (! context.continuousRepaint && ! shouldExit())\r
repaintEvent.wait (-1);\r
+ #endif\r
}\r
\r
hasInitialised = false;\r
if (context.renderer != nullptr)\r
context.renderer->newOpenGLContextCreated();\r
\r
+ #if JUCE_MAC\r
+ CVDisplayLinkCreateWithActiveCGDisplays (&displayLink);\r
+ CVDisplayLinkSetOutputCallback (displayLink, &displayLinkCallback, this);\r
+ CVDisplayLinkStart (displayLink);\r
+ #endif\r
+\r
return true;\r
}\r
\r
void shutdownOnThread()\r
{\r
+ #if JUCE_MAC\r
+ CVDisplayLinkStop (displayLink);\r
+ CVDisplayLinkRelease (displayLink);\r
+ #endif\r
+\r
if (context.renderer != nullptr)\r
context.renderer->openGLContextClosing();\r
\r
\r
void execute (OpenGLContext::AsyncWorker::Ptr workerToUse, bool shouldBlock, bool calledFromDestructor = false)\r
{\r
- if (calledFromDestructor || destroying.get() == 0)\r
+ if (calledFromDestructor || ! destroying)\r
{\r
if (shouldBlock)\r
{\r
#else\r
bool shadersAvailable = false;\r
#endif\r
- bool hasInitialised = false;\r
- Atomic<int> needsUpdate { 1 }, destroying;\r
+ std::atomic<bool> hasInitialised { false }, needsUpdate { true }, destroying { false };\r
uint32 lastMMLockReleaseTime = 0;\r
\r
+ #if JUCE_MAC\r
+ CVDisplayLinkRef displayLink;\r
+ #endif\r
std::unique_ptr<ThreadPool> renderThread;\r
ReferenceCountedArray<OpenGLContext::AsyncWorker, CriticalSection> workQueue;\r
MessageManager::Lock messageManagerLock;\r
This function can only be called if the context is attached to a component.\r
Otherwise, this function will assert.\r
\r
- This function is useful when you need to excute house-keeping tasks such\r
+ This function is useful when you need to execute house-keeping tasks such\r
as allocating, deallocating textures or framebuffers. As such, the functor\r
will execute without locking the message thread. Therefore, it is not\r
intended for any drawing commands or GUI code. Any GUI code should be\r
*/\r
unsigned int getFrameBufferID() const noexcept;\r
\r
- /** Returns an OS-dependent handle to some kind of underlting OS-provided GL context.\r
+ /** Returns an OS-dependent handle to some kind of underlying OS-provided GL context.\r
\r
The exact type of the value returned will depend on the OS and may change\r
if the implementation changes. If you want to use this, digging around in the\r
==============================================================================\r
*/\r
\r
+\r
/*******************************************************************************\r
The block below describes the properties of this module, and is read by\r
the Projucer to automatically generate project code that uses it.\r
\r
BEGIN_JUCE_MODULE_DECLARATION\r
\r
- ID: juce_osc\r
- vendor: juce\r
- version: 5.4.5\r
- name: JUCE OSC classes\r
- description: Open Sound Control implementation.\r
- website: http://www.juce.com/juce\r
- license: GPL/Commercial\r
+ ID: juce_osc\r
+ vendor: juce\r
+ version: 5.4.6\r
+ name: JUCE OSC classes\r
+ description: Open Sound Control implementation.\r
+ website: http://www.juce.com/juce\r
+ license: GPL/Commercial\r
\r
- dependencies: juce_core, juce_events\r
+ dependencies: juce_core, juce_events\r
\r
END_JUCE_MODULE_DECLARATION\r
\r
bool matches (const OSCAddress& address) const noexcept;\r
\r
/** Checks whether the OSCAddressPattern contains any of the allowed OSC\r
- address patttern wildcards: ?, *, [], {}\r
+ address pattern wildcards: ?, *, [], {}\r
\r
@returns true if the OSCAddressPattern contains OSC wildcards, false otherwise.\r
*/\r
*/\r
Time toTime() const noexcept;\r
\r
- /** Returns true if the OSCTimeTag object has the special value representing "immedately". */\r
+ /** Returns true if the OSCTimeTag object has the special value representing "immediately". */\r
bool isImmediately() const noexcept;\r
\r
/** Returns the raw binary OSC time tag representation. */\r
}\r
\r
void InAppPurchases::purchaseProduct (const String& productIdentifier,\r
- bool isSubscription,\r
- const StringArray& upgradeProductIdentifiers,\r
+ const String& upgradeProductIdentifier,\r
bool creditForUnusedSubscription)\r
{\r
#if JUCE_ANDROID || JUCE_IOS || JUCE_MAC\r
- pimpl->purchaseProduct (productIdentifier, isSubscription,\r
- upgradeProductIdentifiers, creditForUnusedSubscription);\r
+ pimpl->purchaseProduct (productIdentifier, upgradeProductIdentifier, creditForUnusedSubscription);\r
#else\r
Listener::PurchaseInfo purchaseInfo { Purchase { "", productIdentifier, {}, {}, {} }, {} };\r
\r
\r
@param productIdentifier The product identifier.\r
\r
- @param isSubscription (Android only) defines if a product a user wants to buy is a subscription or a one-time purchase.\r
- On iOS, type of the product is derived implicitly.\r
-\r
- @param upgradeOrDowngradeFromSubscriptionsWithProductIdentifiers (Android only) specifies subscriptions that will be replaced by the\r
- one being purchased now. Used only when buying a subscription\r
- that is an upgrade or downgrade from other ones.\r
+ @param upgradeOrDowngradeFromSubscriptionsWithProductIdentifier (Android only) specifies the subscription that will be replaced by\r
+ the one being purchased now. Used only when buying a subscription\r
+ that is an upgrade or downgrade from another.\r
\r
@param creditForUnusedSubscription (Android only) controls whether a user should be credited for any unused subscription time on\r
- the products that are being upgraded or downgraded.\r
+ the product that is being upgraded or downgraded.\r
*/\r
void purchaseProduct (const String& productIdentifier,\r
- bool isSubscription,\r
- const StringArray& upgradeOrDowngradeFromSubscriptionsWithProductIdentifiers = {},\r
+ const String& upgradeOrDowngradeFromSubscriptionWithProductIdentifier = {},\r
bool creditForUnusedSubscription = true);\r
\r
/** Asynchronously asks about a list of products that a user has already bought. Upon completion, Listener::purchasesListReceived()\r
/** iOS only: Cancels downloads of hosted content from the store. */\r
void cancelDownloads (const Array<Download*>& downloads);\r
\r
+ //==============================================================================\r
+ // On Android, it is no longer necessary to specify whether the product being purchased is a subscription\r
+ // and only a single subscription can be upgraded/downgraded. Use the updated purchaseProduct() method\r
+ // which takes a single String argument.\r
+ JUCE_DEPRECATED_WITH_BODY (void purchaseProduct (const String& productIdentifier,\r
+ bool isSubscription,\r
+ const StringArray& upgradeOrDowngradeFromSubscriptionsWithProductIdentifiers = {},\r
+ bool creditForUnusedSubscription = true),\r
+ {\r
+\r
+ ignoreUnused (isSubscription);\r
+ purchaseProduct (productIdentifier,\r
+ upgradeOrDowngradeFromSubscriptionsWithProductIdentifiers[0],\r
+ creditForUnusedSubscription);\r
+ })\r
+\r
private:\r
//==============================================================================\r
#ifndef DOXYGEN\r
==============================================================================\r
*/\r
\r
+\r
/*******************************************************************************\r
The block below describes the properties of this module, and is read by\r
the Projucer to automatically generate project code that uses it.\r
\r
BEGIN_JUCE_MODULE_DECLARATION\r
\r
- ID: juce_product_unlocking\r
- vendor: juce\r
- version: 5.4.5\r
- name: JUCE Online marketplace support\r
- description: Classes for online product authentication\r
- website: http://www.juce.com/juce\r
- license: GPL/Commercial\r
+ ID: juce_product_unlocking\r
+ vendor: juce\r
+ version: 5.4.6\r
+ name: JUCE Online marketplace support\r
+ description: Classes for online product authentication\r
+ website: http://www.juce.com/juce\r
+ license: GPL/Commercial\r
\r
- dependencies: juce_cryptography juce_core\r
+ dependencies: juce_cryptography juce_core, juce_events\r
\r
END_JUCE_MODULE_DECLARATION\r
\r
//==============================================================================\r
#include <juce_core/juce_core.h>\r
#include <juce_cryptography/juce_cryptography.h>\r
+#include <juce_events/juce_events.h>\r
\r
#if JUCE_MODULE_AVAILABLE_juce_data_structures\r
#include <juce_data_structures/juce_data_structures.h>\r
namespace juce\r
{\r
\r
-/** Acts as a GUI which asks the user for their details, and calls the approriate\r
+/** Acts as a GUI which asks the user for their details, and calls the appropriate\r
methods on your OnlineUnlockStatus object to attempt to register the app.\r
\r
You should create one of these components and add it to your parent window,\r
--- /dev/null
+package com.roli.juce;\r
+\r
+import com.android.billingclient.api.*;\r
+\r
+public class JuceBillingClient implements PurchasesUpdatedListener {\r
+ private native void skuDetailsQueryCallback(long host, java.util.List<SkuDetails> skuDetails);\r
+ private native void purchasesListQueryCallback(long host, java.util.List<Purchase> purchases);\r
+ private native void purchaseCompletedCallback(long host, Purchase purchase, int responseCode);\r
+ private native void purchaseConsumedCallback(long host, String productIdentifier, int responseCode);\r
+\r
+ public JuceBillingClient(android.content.Context context, long hostToUse) {\r
+ host = hostToUse;\r
+\r
+ billingClient = BillingClient.newBuilder(context)\r
+ .enablePendingPurchases()\r
+ .setListener(this)\r
+ .build();\r
+\r
+ billingClient.startConnection(null);\r
+ }\r
+\r
+ public void endConnection() {\r
+ billingClient.endConnection();\r
+ }\r
+\r
+ public boolean isReady() {\r
+ return billingClient.isReady();\r
+ }\r
+\r
+ public boolean isBillingSupported() {\r
+ return billingClient.isFeatureSupported(BillingClient.FeatureType.SUBSCRIPTIONS).getResponseCode()\r
+ == BillingClient.BillingResponseCode.OK;\r
+ }\r
+\r
+ public void querySkuDetails(final String[] skusToQuery) {\r
+ executeOnBillingClientConnection(new Runnable() {\r
+ @Override\r
+ public void run() {\r
+ final java.util.List<String> skuList = java.util.Arrays.asList(skusToQuery);\r
+\r
+ SkuDetailsParams.Builder params = SkuDetailsParams.newBuilder()\r
+ .setSkusList(skuList)\r
+ .setType(BillingClient.SkuType.INAPP);\r
+\r
+ billingClient.querySkuDetailsAsync(params.build(), new SkuDetailsResponseListener() {\r
+ @Override\r
+ public void onSkuDetailsResponse(BillingResult billingResult, final java.util.List<SkuDetails> inAppSkuDetails) {\r
+ if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK) {\r
+ SkuDetailsParams.Builder params = SkuDetailsParams.newBuilder()\r
+ .setSkusList(skuList)\r
+ .setType(BillingClient.SkuType.SUBS);\r
+\r
+ billingClient.querySkuDetailsAsync(params.build(), new SkuDetailsResponseListener() {\r
+ @Override\r
+ public void onSkuDetailsResponse(BillingResult billingResult, java.util.List<SkuDetails> subsSkuDetails) {\r
+ if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK) {\r
+ subsSkuDetails.addAll(inAppSkuDetails);\r
+ skuDetailsQueryCallback(host, subsSkuDetails);\r
+ }\r
+ }\r
+ });\r
+ }\r
+ }\r
+ });\r
+ }\r
+ });\r
+ }\r
+\r
+ public void launchBillingFlow(final android.app.Activity activity, final BillingFlowParams params) {\r
+ executeOnBillingClientConnection(new Runnable() {\r
+ @Override\r
+ public void run() {\r
+ BillingResult r = billingClient.launchBillingFlow(activity, params);\r
+ }\r
+ });\r
+ }\r
+\r
+ public void queryPurchases() {\r
+ executeOnBillingClientConnection(new Runnable() {\r
+ @Override\r
+ public void run() {\r
+ Purchase.PurchasesResult inAppPurchases = billingClient.queryPurchases(BillingClient.SkuType.INAPP);\r
+ Purchase.PurchasesResult subsPurchases = billingClient.queryPurchases(BillingClient.SkuType.SUBS);\r
+\r
+ if (inAppPurchases.getResponseCode() == BillingClient.BillingResponseCode.OK\r
+ && subsPurchases.getResponseCode() == BillingClient.BillingResponseCode.OK) {\r
+ java.util.List<Purchase> purchaseList = inAppPurchases.getPurchasesList();\r
+ purchaseList.addAll(subsPurchases.getPurchasesList());\r
+\r
+ purchasesListQueryCallback(host, purchaseList);\r
+ return;\r
+ }\r
+\r
+ purchasesListQueryCallback(host, null);\r
+ }\r
+ });\r
+ }\r
+\r
+ public void consumePurchase(final String productIdentifier, final String purchaseToken) {\r
+ executeOnBillingClientConnection(new Runnable() {\r
+ @Override\r
+ public void run() {\r
+ ConsumeParams consumeParams = ConsumeParams.newBuilder()\r
+ .setPurchaseToken(purchaseToken)\r
+ .build();\r
+\r
+ billingClient.consumeAsync(consumeParams, new ConsumeResponseListener() {\r
+ @Override\r
+ public void onConsumeResponse(BillingResult billingResult, String purchaseToken) {\r
+ purchaseConsumedCallback(host, productIdentifier, billingResult.getResponseCode());\r
+ }\r
+ });\r
+ }\r
+ });\r
+ }\r
+\r
+ @Override\r
+ public void onPurchasesUpdated(BillingResult result, java.util.List<Purchase> purchases) {\r
+ int responseCode = result.getResponseCode();\r
+\r
+ if (purchases != null) {\r
+ for (Purchase purchase : purchases) {\r
+ handlePurchase(purchase, responseCode);\r
+ }\r
+ } else {\r
+ purchaseCompletedCallback(host, null, responseCode);\r
+ }\r
+ }\r
+\r
+ private void executeOnBillingClientConnection(Runnable runnable) {\r
+ if (billingClient.isReady()) {\r
+ runnable.run();\r
+ } else {\r
+ connectAndExecute(runnable);\r
+ }\r
+ }\r
+\r
+ private void connectAndExecute(final Runnable executeOnSuccess) {\r
+ billingClient.startConnection(new BillingClientStateListener() {\r
+ @Override\r
+ public void onBillingSetupFinished(BillingResult billingResponse) {\r
+ if (billingResponse.getResponseCode() == BillingClient.BillingResponseCode.OK) {\r
+ if (executeOnSuccess != null) {\r
+ executeOnSuccess.run();\r
+ }\r
+ }\r
+ }\r
+\r
+ @Override\r
+ public void onBillingServiceDisconnected() {\r
+ }\r
+ });\r
+ }\r
+\r
+ private void handlePurchase(final Purchase purchase, final int responseCode) {\r
+ purchaseCompletedCallback(host, purchase, responseCode);\r
+\r
+ if (responseCode == BillingClient.BillingResponseCode.OK\r
+ && purchase.getPurchaseState() == Purchase.PurchaseState.PURCHASED\r
+ && !purchase.isAcknowledged()) {\r
+ executeOnBillingClientConnection(new Runnable() {\r
+ @Override\r
+ public void run() {\r
+ AcknowledgePurchaseParams acknowledgePurchaseParams = AcknowledgePurchaseParams.newBuilder().setPurchaseToken(purchase.getPurchaseToken()).build();\r
+ billingClient.acknowledgePurchase(acknowledgePurchaseParams, null);\r
+ }\r
+ });\r
+ }\r
+ }\r
+\r
+ private long host = 0;\r
+ private BillingClient billingClient;\r
+}\r
{\r
\r
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \\r
- METHOD (isBillingSupported, "isBillingSupported", "(ILjava/lang/String;Ljava/lang/String;)I") \\r
- METHOD (getSkuDetails, "getSkuDetails", "(ILjava/lang/String;Ljava/lang/String;Landroid/os/Bundle;)Landroid/os/Bundle;") \\r
- METHOD (getBuyIntent, "getBuyIntent", "(ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Landroid/os/Bundle;") \\r
- METHOD (getBuyIntentExtraParams, "getBuyIntentExtraParams", "(ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Landroid/os/Bundle;)Landroid/os/Bundle;") \\r
- METHOD (getPurchases, "getPurchases", "(ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)Landroid/os/Bundle;") \\r
- METHOD (consumePurchase, "consumePurchase", "(ILjava/lang/String;Ljava/lang/String;)I") \\r
- METHOD (getPurchaseHistory, "getPurchaseHistory", "(ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;Landroid/os/Bundle;)Landroid/os/Bundle;")\r
-\r
-DECLARE_JNI_CLASS (IInAppBillingService, "com/android/vending/billing/IInAppBillingService")\r
+ METHOD (getSku, "getSku", "()Ljava/lang/String;") \\r
+ METHOD (getTitle, "getTitle", "()Ljava/lang/String;") \\r
+ METHOD (getDescription, "getDescription", "()Ljava/lang/String;") \\r
+ METHOD (getPrice, "getPrice", "()Ljava/lang/String;") \\r
+ METHOD (getPriceCurrencyCode, "getPriceCurrencyCode", "()Ljava/lang/String;")\r
+\r
+DECLARE_JNI_CLASS (SkuDetails, "com/android/billingclient/api/SkuDetails")\r
#undef JNI_CLASS_MEMBERS\r
\r
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \\r
- STATICMETHOD (asInterface, "asInterface", "(Landroid/os/IBinder;)Lcom/android/vending/billing/IInAppBillingService;") \\r
+ STATICMETHOD (newBuilder, "newBuilder", "()Lcom/android/billingclient/api/BillingFlowParams$Builder;")\r
\r
-DECLARE_JNI_CLASS (IInAppBillingServiceStub, "com/android/vending/billing/IInAppBillingService$Stub")\r
+DECLARE_JNI_CLASS (BillingFlowParams, "com/android/billingclient/api/BillingFlowParams")\r
#undef JNI_CLASS_MEMBERS\r
\r
-//==============================================================================\r
-struct ServiceConnection : public AndroidInterfaceImplementer\r
-{\r
- virtual void onServiceConnected (jobject component, jobject iBinder) = 0;\r
- virtual void onServiceDisconnected (jobject component) = 0;\r
-\r
- jobject invoke (jobject proxy, jobject method, jobjectArray args) override\r
- {\r
- auto* env = getEnv();\r
- auto methodName = juceString ((jstring) env->CallObjectMethod (method, JavaMethod.getName));\r
+#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \\r
+ METHOD (build, "build", "()Lcom/android/billingclient/api/BillingFlowParams;") \\r
+ METHOD (setOldSku, "setOldSku", "(Ljava/lang/String;Ljava/lang/String;)Lcom/android/billingclient/api/BillingFlowParams$Builder;") \\r
+ METHOD (setReplaceSkusProrationMode, "setReplaceSkusProrationMode", "(I)Lcom/android/billingclient/api/BillingFlowParams$Builder;") \\r
+ METHOD (setSkuDetails, "setSkuDetails", "(Lcom/android/billingclient/api/SkuDetails;)Lcom/android/billingclient/api/BillingFlowParams$Builder;")\r
\r
- if (methodName == "onServiceConnected")\r
- {\r
- onServiceConnected (env->GetObjectArrayElement (args, 0),\r
- env->GetObjectArrayElement (args, 1));\r
- return nullptr;\r
- }\r
+DECLARE_JNI_CLASS (BillingFlowParamsBuilder, "com/android/billingclient/api/BillingFlowParams$Builder")\r
+#undef JNI_CLASS_MEMBERS\r
\r
- if (methodName == "onServiceDisconnected")\r
- {\r
- onServiceDisconnected (env->GetObjectArrayElement (args, 0));\r
- return nullptr;\r
- }\r
+#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \\r
+ METHOD (getOrderId, "getOrderId", "()Ljava/lang/String;") \\r
+ METHOD (getSku, "getSku", "()Ljava/lang/String;") \\r
+ METHOD (getPackageName, "getPackageName", "()Ljava/lang/String;") \\r
+ METHOD (getPurchaseTime, "getPurchaseTime", "()J") \\r
+ METHOD (getPurchaseToken, "getPurchaseToken", "()Ljava/lang/String;")\r
\r
- return AndroidInterfaceImplementer::invoke (proxy, method, args);\r
- }\r
-};\r
+DECLARE_JNI_CLASS (AndroidPurchase, "com/android/billingclient/api/Purchase")\r
+#undef JNI_CLASS_MEMBERS\r
\r
//==============================================================================\r
-struct InAppPurchases::Pimpl : private AsyncUpdater,\r
- private ServiceConnection\r
+struct InAppPurchases::Pimpl\r
{\r
- Pimpl (InAppPurchases& parent) : owner (parent)\r
+ Pimpl (InAppPurchases& parent)\r
+ : owner (parent),\r
+ billingClient (LocalRef<jobject> (getEnv()->NewObject (JuceBillingClient,\r
+ JuceBillingClient.constructor,\r
+ getAppContext().get(),\r
+ (jlong) this)))\r
{\r
- auto* env = getEnv();\r
- auto intent = env->NewObject (AndroidIntent, AndroidIntent.constructWithString,\r
- javaString ("com.android.vending.billing.InAppBillingService.BIND").get());\r
- env->CallObjectMethod (intent, AndroidIntent.setPackage, javaString ("com.android.vending").get());\r
-\r
- serviceConnection = GlobalRef (CreateJavaInterface (this, "android/content/ServiceConnection"));\r
-\r
- env->CallBooleanMethod (getCurrentActivity().get(), AndroidContext.bindService, intent,\r
- serviceConnection.get(), 1 /*BIND_AUTO_CREATE*/);\r
-\r
- if (threadPool == nullptr)\r
- threadPool.reset (new ThreadPool (1));\r
}\r
\r
~Pimpl()\r
{\r
- threadPool = nullptr;\r
-\r
- if (serviceConnection != nullptr)\r
- {\r
- getEnv()->CallVoidMethod (getCurrentActivity().get(), AndroidContext.unbindService, serviceConnection.get());\r
- serviceConnection.clear();\r
- }\r
+ getEnv()->CallVoidMethod (billingClient, JuceBillingClient.endConnection);\r
}\r
\r
//==============================================================================\r
- bool isInAppPurchasesSupported() { return isInAppPurchasesSupported (inAppBillingService); }\r
+ bool isInAppPurchasesSupported() const\r
+ {\r
+ return isReady() && getEnv()->CallBooleanMethod (billingClient, JuceBillingClient.isBillingSupported);\r
+ }\r
\r
void getProductsInformation (const StringArray& productIdentifiers)\r
{\r
- auto callback = [this](const Array<InAppPurchases::Product>& products)\r
+ skuDetailsQueryCallbackQueue.emplace ([this] (LocalRef<jobject> skuDetailsList)\r
{\r
- const ScopedLock lock (getProductsInformationJobResultsLock);\r
- getProductsInformationJobResults.insert (0, products);\r
- triggerAsyncUpdate();\r
- };\r
+ if (skuDetailsList != nullptr)\r
+ {\r
+ auto* env = getEnv();\r
+ Array<InAppPurchases::Product> products;\r
+\r
+ for (int i = 0; i < env->CallIntMethod (skuDetailsList, JavaList.size); ++i)\r
+ products.add (buildProduct (LocalRef<jobject> (env->CallObjectMethod (skuDetailsList, JavaList.get, i))));\r
+\r
+ owner.listeners.call ([&] (Listener& l) { l.productsInfoReturned (products); });\r
+ }\r
+ });\r
\r
- threadPool->addJob (new GetProductsInformationJob (*this, getPackageName(),\r
- productIdentifiers, callback), true);\r
+ querySkuDetailsAsync (convertToLowerCase (productIdentifiers));\r
}\r
\r
- void purchaseProduct (const String& productIdentifier, bool isSubscription,\r
- const StringArray& subscriptionIdentifiers, bool creditForUnusedSubscription)\r
+ void purchaseProduct (const String& productIdentifier,\r
+ const String& subscriptionIdentifier,\r
+ bool creditForUnusedSubscription)\r
{\r
- // Upgrading/downgrading only makes sense for subscriptions!\r
- jassert (subscriptionIdentifiers.isEmpty() || isSubscription);\r
+ skuDetailsQueryCallbackQueue.emplace ([=] (LocalRef<jobject> skuDetailsList)\r
+ {\r
+ if (skuDetailsList != nullptr)\r
+ {\r
+ auto* env = getEnv();\r
\r
- auto buyIntentBundle = getBuyIntentBundle (productIdentifier, isSubscription,\r
- subscriptionIdentifiers, creditForUnusedSubscription);\r
- auto* env = getEnv();\r
+ if (env->CallIntMethod (skuDetailsList, JavaList.size) > 0)\r
+ {\r
+ LocalRef<jobject> skuDetails (env->CallObjectMethod (skuDetailsList, JavaList.get, 0));\r
\r
- auto responseCodeString = javaString ("RESPONSE_CODE");\r
- auto responseCode = env->CallIntMethod (buyIntentBundle.get(), AndroidBundle.getInt, responseCodeString.get());\r
+ if (subscriptionIdentifier.isNotEmpty())\r
+ changeExistingSubscription (skuDetails, subscriptionIdentifier, creditForUnusedSubscription);\r
+ else\r
+ purchaseProductWithSkuDetails (skuDetails);\r
+ }\r
+ }\r
+ });\r
\r
- if (responseCode == 0)\r
- {\r
- auto buyIntentString = javaString ("BUY_INTENT");\r
- auto pendingIntent = LocalRef<jobject> (env->CallObjectMethod (buyIntentBundle.get(), AndroidBundle.getParcelable, buyIntentString.get()));\r
-\r
- auto requestCode = 1001;\r
- auto intentSender = LocalRef<jobject> (env->CallObjectMethod (pendingIntent.get(), AndroidPendingIntent.getIntentSender));\r
- auto fillInIntent = LocalRef<jobject> (env->NewObject (AndroidIntent, AndroidIntent.constructor));\r
- auto flagsMask = LocalRef<jobject> (env->CallStaticObjectMethod (JavaInteger, JavaInteger.valueOf, 0));\r
- auto flagsValues = LocalRef<jobject> (env->CallStaticObjectMethod (JavaInteger, JavaInteger.valueOf, 0));\r
- auto extraFlags = LocalRef<jobject> (env->CallStaticObjectMethod (JavaInteger, JavaInteger.valueOf, 0));\r
-\r
- env->CallVoidMethod (getCurrentActivity().get(), AndroidActivity.startIntentSenderForResult, intentSender.get(), requestCode,\r
- fillInIntent.get(), flagsMask.get(), flagsValues.get(), extraFlags.get());\r
- }\r
- else if (responseCode == 7)\r
- {\r
- // Item already bought.\r
- notifyAboutPurchaseResult ({ {}, productIdentifier, juceString (getPackageName()), {}, {} }, true, statusCodeToUserString (responseCode));\r
- }\r
+ querySkuDetailsAsync (convertToLowerCase ({ productIdentifier }));\r
}\r
\r
void restoreProductsBoughtList (bool, const juce::String&)\r
{\r
- auto callback = [this](const GetProductsBoughtJob::Result& r)\r
+ purchasesListQueryCallbackQueue.emplace ([this] (LocalRef<jobject> purchasesList)\r
{\r
- const ScopedLock lock (getProductsBoughtJobResultsLock);\r
- getProductsBoughtJobResults.insert (0, r);\r
- triggerAsyncUpdate();\r
- };\r
+ if (purchasesList != nullptr)\r
+ {\r
+ auto* env = getEnv();\r
+ Array<InAppPurchases::Listener::PurchaseInfo> purchases;\r
+\r
+ for (int i = 0; i < env->CallIntMethod (purchasesList, JavaArrayList.size); ++i)\r
+ {\r
+ LocalRef<jobject> purchase (env->CallObjectMethod (purchasesList, JavaArrayList.get, i));\r
+ purchases.add ({ buildPurchase (purchase), {} });\r
+ }\r
+\r
+ owner.listeners.call ([&] (Listener& l) { l.purchasesListRestored (purchases, true, NEEDS_TRANS ("Success")); });\r
+ }\r
+ else\r
+ {\r
+ owner.listeners.call ([&] (Listener& l) { l.purchasesListRestored ({}, false, NEEDS_TRANS ("Failure")); });\r
+ }\r
+ });\r
\r
- threadPool->addJob (new GetProductsBoughtJob (*this,\r
- getPackageName(), callback), true);\r
+ getProductsBoughtAsync();\r
}\r
\r
void consumePurchase (const String& productIdentifier, const String& purchaseToken)\r
{\r
- auto callback = [this](const ConsumePurchaseJob::Result& r)\r
+ if (purchaseToken.isEmpty())\r
{\r
- const ScopedLock lock (consumePurchaseJobResultsLock);\r
- consumePurchaseJobResults.insert (0, r);\r
- triggerAsyncUpdate();\r
- };\r
+ skuDetailsQueryCallbackQueue.emplace ([=] (LocalRef<jobject> skuDetailsList)\r
+ {\r
+ if (skuDetailsList != nullptr)\r
+ {\r
+ auto* env = getEnv();\r
+\r
+ if (env->CallIntMethod (skuDetailsList, JavaList.size) > 0)\r
+ {\r
+ LocalRef<jobject> sku (env->CallObjectMethod (skuDetailsList, JavaList.get, 0));\r
+\r
+ auto token = juceString (LocalRef<jstring> ((jstring) env->CallObjectMethod (sku, AndroidPurchase.getSku)));\r
+\r
+ if (token.isNotEmpty())\r
+ {\r
+ consumePurchaseWithToken (productIdentifier, token);\r
+ return;\r
+ }\r
+ }\r
+ }\r
+\r
+ notifyListenersAboutConsume (productIdentifier, false, NEEDS_TRANS ("Item unavailable"));\r
+ });\r
+\r
+ querySkuDetailsAsync (convertToLowerCase ({ productIdentifier }));\r
+ }\r
\r
- threadPool->addJob (new ConsumePurchaseJob (*this, getPackageName(), productIdentifier,\r
- purchaseToken, callback), true);\r
+ consumePurchaseWithToken (productIdentifier, purchaseToken);\r
}\r
\r
//==============================================================================\r
- void startDownloads (const Array<Download*>& downloads)\r
+ void startDownloads (const Array<Download*>& downloads)\r
{\r
// Not available on this platform.\r
ignoreUnused (downloads);\r
jassertfalse;\r
}\r
\r
- void pauseDownloads (const Array<Download*>& downloads)\r
+ void pauseDownloads (const Array<Download*>& downloads)\r
{\r
// Not available on this platform.\r
ignoreUnused (downloads);\r
jassertfalse;\r
}\r
\r
- void resumeDownloads (const Array<Download*>& downloads)\r
+ void resumeDownloads (const Array<Download*>& downloads)\r
{\r
// Not available on this platform.\r
ignoreUnused (downloads);\r
jassertfalse;\r
}\r
\r
- void cancelDownloads (const Array<Download*>& downloads)\r
+ void cancelDownloads (const Array<Download*>& downloads)\r
{\r
// Not available on this platform.\r
ignoreUnused (downloads);\r
jassertfalse;\r
}\r
\r
- //==============================================================================\r
- LocalRef<jobject> getBuyIntentBundle (const String& productIdentifier, bool isSubscription,\r
- const StringArray& subscriptionIdentifiers, bool creditForUnusedSubscription)\r
+private:\r
+ #define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \\r
+ METHOD (constructor, "<init>", "(Landroid/content/Context;J)V") \\r
+ METHOD (endConnection, "endConnection", "()V") \\r
+ METHOD (isReady, "isReady", "()Z") \\r
+ METHOD (isBillingSupported, "isBillingSupported", "()Z") \\r
+ METHOD (querySkuDetails, "querySkuDetails", "([Ljava/lang/String;)V") \\r
+ METHOD (launchBillingFlow, "launchBillingFlow", "(Landroid/app/Activity;Lcom/android/billingclient/api/BillingFlowParams;)V") \\r
+ METHOD (queryPurchases, "queryPurchases", "()V") \\r
+ METHOD (consumePurchase, "consumePurchase", "(Ljava/lang/String;Ljava/lang/String;)V") \\r
+ \\r
+ CALLBACK (skuDetailsQueryCallback, "skuDetailsQueryCallback", "(JLjava/util/List;)V") \\r
+ CALLBACK (purchasesListQueryCallback, "purchasesListQueryCallback", "(JLjava/util/List;)V") \\r
+ CALLBACK (purchaseCompletedCallback, "purchaseCompletedCallback", "(JLcom/android/billingclient/api/Purchase;I)V") \\r
+ CALLBACK (purchaseConsumedCallback, "purchaseConsumedCallback", "(JLjava/lang/String;I)V")\r
+\r
+ DECLARE_JNI_CLASS (JuceBillingClient, "com/roli/juce/JuceBillingClient")\r
+ #undef JNI_CLASS_MEMBERS\r
+\r
+ static void JNICALL skuDetailsQueryCallback (JNIEnv*, jobject, jlong host, jobject skuDetailsList)\r
{\r
- auto* env = getEnv();\r
-\r
- auto skuString = javaString (productIdentifier);\r
- auto productTypeString = javaString (isSubscription ? "subs" : "inapp");\r
- auto devString = javaString ("");\r
-\r
- if (subscriptionIdentifiers.isEmpty())\r
- return LocalRef<jobject> (inAppBillingService.callObjectMethod (IInAppBillingService.getBuyIntent, 3,\r
- getPackageName().get(), skuString.get(),\r
- productTypeString.get(), devString.get()));\r
-\r
- auto skuList = LocalRef<jobject> (env->NewObject (JavaArrayList, JavaArrayList.constructor,\r
- (int) subscriptionIdentifiers.size()));\r
-\r
- if (skuList.get() == 0)\r
- {\r
- jassertfalse;\r
- return LocalRef<jobject> (0);\r
- }\r
-\r
- for (const auto& identifier : subscriptionIdentifiers)\r
- env->CallBooleanMethod (skuList.get(), JavaArrayList.add, javaString (identifier).get());\r
-\r
- auto extraParams = LocalRef<jobject> (env->NewObject (AndroidBundle, AndroidBundle.constructor));\r
-\r
- if (extraParams.get() == 0)\r
- {\r
- jassertfalse;\r
- return LocalRef<jobject> (0);\r
- }\r
-\r
- auto skusToReplaceString = javaString ("skusToReplace");\r
- auto replaceSkusProrationString = javaString ("replaceSkusProration");\r
+ if (auto* myself = reinterpret_cast<Pimpl*> (host))\r
+ myself->updateSkuDetails (skuDetailsList);\r
+ }\r
\r
- env->CallVoidMethod (extraParams.get(), AndroidBundle.putStringArrayList, skusToReplaceString.get(), skuList.get());\r
- env->CallVoidMethod (extraParams.get(), AndroidBundle.putBoolean, replaceSkusProrationString.get(), creditForUnusedSubscription);\r
+ static void JNICALL purchasesListQueryCallback (JNIEnv*, jobject, jlong host, jobject purchasesList)\r
+ {\r
+ if (auto* myself = reinterpret_cast<Pimpl*> (host))\r
+ myself->updatePurchasesList (purchasesList);\r
+ }\r
\r
- return LocalRef<jobject> (inAppBillingService.callObjectMethod (IInAppBillingService.getBuyIntentExtraParams, 6,\r
- getPackageName().get(), skuString.get(),\r
- productTypeString.get(), devString.get(),\r
- extraParams.get()));\r
+ static void JNICALL purchaseCompletedCallback (JNIEnv*, jobject, jlong host, jobject purchase, int responseCode)\r
+ {\r
+ if (auto* myself = reinterpret_cast<Pimpl*> (host))\r
+ myself->purchaseCompleted (purchase, responseCode);\r
}\r
\r
- //==============================================================================\r
- void notifyAboutPurchaseResult (const InAppPurchases::Purchase& purchase, bool success, const String& statusDescription)\r
+ static void JNICALL purchaseConsumedCallback (JNIEnv*, jobject, jlong host, jstring productIdentifier, int responseCode)\r
{\r
- owner.listeners.call ([&] (Listener& l) { l.productPurchaseFinished ({ purchase, {} }, success, statusDescription); });\r
+ if (auto* myself = reinterpret_cast<Pimpl*> (host))\r
+ myself->purchaseConsumed (productIdentifier, responseCode);\r
}\r
\r
//==============================================================================\r
- bool checkIsReady()\r
+ bool isReady() const\r
{\r
- // It may take a few seconds for the in-app purchase service to connect\r
- for (auto retries = 0; retries < 10 && inAppBillingService.get() == 0; ++retries)\r
- Thread::sleep (500);\r
-\r
- return (inAppBillingService.get() != 0);\r
+ return getEnv()->CallBooleanMethod (billingClient, JuceBillingClient.isReady);\r
}\r
\r
- static bool isInAppPurchasesSupported (jobject iapService)\r
+ bool checkIsReady() const\r
{\r
- if (iapService != nullptr)\r
+ for (int i = 0; i < 10; ++i)\r
{\r
- auto* env = getEnv();\r
-\r
- auto inAppString = javaString ("inapp");\r
- auto subsString = javaString ("subs");\r
-\r
- if (env->CallIntMethod (iapService, IInAppBillingService.isBillingSupported, 3,\r
- getPackageName().get(), inAppString.get()) != 0)\r
- return false;\r
+ if (isReady())\r
+ return true;\r
\r
- if (env->CallIntMethod (iapService, IInAppBillingService.isBillingSupported, 3,\r
- getPackageName().get(), subsString.get()) != 0)\r
- return false;\r
-\r
- return true;\r
+ Thread::sleep (500);\r
}\r
\r
- // Connecting to the in-app purchase server failed! This could have multiple reasons:\r
- // 1) Your phone/emulator must support the google play store\r
- // 2) Your phone must be logged into the google play store and be able to receive updates\r
- // 3) It can take a few seconds after instantiation of the InAppPurchase class for\r
- // in-app purchases to be avaialable on Android.\r
return false;\r
}\r
\r
//==============================================================================\r
- void onServiceConnected (jobject, jobject iBinder) override\r
+ static StringArray convertToLowerCase (const StringArray& stringsToConvert)\r
{\r
- auto* env = getEnv();\r
-\r
- LocalRef<jobject> iapService (env->CallStaticObjectMethod (IInAppBillingServiceStub,\r
- IInAppBillingServiceStub.asInterface,\r
- iBinder));\r
+ StringArray lowerCase;\r
\r
- if (isInAppPurchasesSupported (iapService))\r
- inAppBillingService = GlobalRef (iapService);\r
+ for (auto& s : stringsToConvert)\r
+ lowerCase.add (s.toLowerCase());\r
\r
- // If you hit this assert, then in-app purchases is not available on your device,\r
- // most likely due to too old version of Google Play API (hint: update Google Play on the device).\r
- jassert (isInAppPurchasesSupported());\r
+ return lowerCase;\r
}\r
\r
- void onServiceDisconnected (jobject) override\r
- {\r
- inAppBillingService.clear();\r
- }\r
-\r
- //==============================================================================\r
- static LocalRef<jstring> getPackageName()\r
+ void querySkuDetailsAsync (const StringArray& productIdentifiers)\r
{\r
- return LocalRef<jstring> ((jstring) (getEnv()->CallObjectMethod (getAppContext().get(), AndroidContext.getPackageName)));\r
- }\r
-\r
- //==============================================================================\r
- struct GetProductsInformationJob : public ThreadPoolJob\r
- {\r
- using Callback = std::function<void(const Array<InAppPurchases::Product>&)>;\r
-\r
- GetProductsInformationJob (Pimpl& parent,\r
- const LocalRef<jstring>& packageNameToUse,\r
- const StringArray& productIdentifiersToUse,\r
- const Callback& callbackToUse)\r
- : ThreadPoolJob ("GetProductsInformationJob"),\r
- owner (parent),\r
- packageName (LocalRef<jobject> (getEnv()->NewLocalRef (packageNameToUse.get()))),\r
- productIdentifiers (productIdentifiersToUse),\r
- callback (callbackToUse)\r
- {}\r
-\r
- ThreadPoolJob::JobStatus runJob() override\r
+ Thread::launch ([=]\r
{\r
- jassert (callback);\r
-\r
- if (owner.checkIsReady())\r
- {\r
- // Google's Billing API limitation\r
- auto maxQuerySize = 20;\r
- auto pi = 0;\r
-\r
- Array<InAppPurchases::Product> results;\r
- StringArray identifiersToUse;\r
-\r
- for (auto i = 0; i < productIdentifiers.size(); ++i)\r
- {\r
- identifiersToUse.add (productIdentifiers[i].toLowerCase());\r
- ++pi;\r
+ if (! checkIsReady())\r
+ return;\r
\r
- if (pi == maxQuerySize || i == productIdentifiers.size() - 1)\r
- {\r
- auto inAppProducts = processRetrievedProducts (queryProductsInformationFromService (identifiersToUse, "inapp"));\r
- auto subsProducts = processRetrievedProducts (queryProductsInformationFromService (identifiersToUse, "subs"));\r
-\r
- results.addArray (inAppProducts);\r
- results.addArray (subsProducts);\r
- identifiersToUse.clear();\r
- pi = 0;\r
- }\r
- }\r
-\r
- if (callback)\r
- callback (results);\r
- }\r
- else\r
+ MessageManager::callAsync ([=]\r
{\r
- if (callback)\r
- callback ({});\r
- }\r
-\r
- return jobHasFinished;\r
- }\r
-\r
- private:\r
- LocalRef<jobject> queryProductsInformationFromService (const StringArray& productIdentifiersToQuery, const String& productType)\r
- {\r
- auto* env = getEnv();\r
-\r
- auto skuList = LocalRef<jobject> (env->NewObject (JavaArrayList, JavaArrayList.constructor, productIdentifiersToQuery.size()));\r
-\r
- if (skuList.get() == 0)\r
- return LocalRef<jobject> (0);\r
-\r
- for (const auto& pi : productIdentifiersToQuery)\r
- env->CallBooleanMethod (skuList.get(), JavaArrayList.add, javaString (pi).get());\r
-\r
- auto querySkus = LocalRef<jobject> (env->NewObject (AndroidBundle, AndroidBundle.constructor));\r
-\r
- if (querySkus.get() == 0)\r
- return LocalRef<jobject> (0);\r
-\r
- auto itemIdListString = javaString ("ITEM_ID_LIST");\r
-\r
- env->CallVoidMethod (querySkus.get(), AndroidBundle.putStringArrayList, itemIdListString.get(), skuList.get());\r
-\r
- auto productTypeString = javaString (productType);\r
-\r
- auto productDetails = LocalRef<jobject> (owner.inAppBillingService.callObjectMethod (IInAppBillingService.getSkuDetails,\r
- 3, (jstring) packageName.get(),\r
- productTypeString.get(), querySkus.get()));\r
-\r
- return productDetails;\r
- }\r
+ getEnv()->CallVoidMethod (billingClient,\r
+ JuceBillingClient.querySkuDetails,\r
+ juceStringArrayToJava (productIdentifiers).get());\r
+ });\r
+ });\r
+ }\r
\r
- Array<InAppPurchases::Product> processRetrievedProducts (LocalRef<jobject> retrievedProducts)\r
+ void getProductsBoughtAsync()\r
+ {\r
+ Thread::launch ([=]\r
{\r
- Array<InAppPurchases::Product> products;\r
+ if (! checkIsReady())\r
+ return;\r
\r
- if (owner.checkIsReady())\r
+ MessageManager::callAsync ([=]\r
{\r
- auto* env = getEnv();\r
-\r
- auto responseCodeString = javaString ("RESPONSE_CODE");\r
-\r
- auto responseCode = env->CallIntMethod (retrievedProducts.get(), AndroidBundle.getInt, responseCodeString.get());\r
-\r
- if (responseCode == 0)\r
- {\r
- auto detailsListString = javaString ("DETAILS_LIST");\r
-\r
- auto responseList = LocalRef<jobject> (env->CallObjectMethod (retrievedProducts.get(), AndroidBundle.getStringArrayList,\r
- detailsListString.get()));\r
-\r
- if (responseList != 0)\r
- {\r
- auto iterator = LocalRef<jobject> (env->CallObjectMethod (responseList.get(), JavaArrayList.iterator));\r
-\r
- if (iterator.get() != 0)\r
- {\r
- for (;;)\r
- {\r
- if (! env->CallBooleanMethod (iterator, JavaIterator.hasNext))\r
- break;\r
-\r
- auto response = juce::LocalRef<jstring> ((jstring)env->CallObjectMethod (iterator, JavaIterator.next));\r
-\r
- if (response.get() != 0)\r
- {\r
- var responseData = JSON::parse (juceString (response.get()));\r
-\r
- if (DynamicObject* object = responseData.getDynamicObject())\r
- {\r
- NamedValueSet& props = object->getProperties();\r
-\r
- static Identifier productIdIdentifier ("productId");\r
- static Identifier titleIdentifier ("title");\r
- static Identifier descriptionIdentifier ("description");\r
- static Identifier priceIdentifier ("price");\r
- static Identifier priceCurrencyCodeIdentifier ("price_currency_code");\r
-\r
- var productId = props[productIdIdentifier];\r
- var title = props[titleIdentifier];\r
- var description = props[descriptionIdentifier];\r
- var price = props[priceIdentifier];\r
- var priceCurrencyCode = props[priceCurrencyCodeIdentifier];\r
-\r
- products.add ( { productId.toString(),\r
- title.toString(),\r
- description.toString(),\r
- price.toString(),\r
- priceCurrencyCode.toString() } );\r
- }\r
-\r
- }\r
- }\r
- }\r
- }\r
- }\r
- }\r
-\r
- return products;\r
- }\r
-\r
- Pimpl& owner;\r
- GlobalRef packageName;\r
- const StringArray productIdentifiers;\r
- Callback callback;\r
- };\r
+ getEnv()->CallVoidMethod (billingClient,\r
+ JuceBillingClient.queryPurchases);\r
+ });\r
+ });\r
+ }\r
\r
//==============================================================================\r
- struct GetProductsBoughtJob : public ThreadPoolJob\r
+ void notifyListenersAboutPurchase (const InAppPurchases::Purchase& purchase, bool success, const String& statusDescription)\r
{\r
- struct Result\r
- {\r
- bool success = false;\r
- Array<InAppPurchases::Listener::PurchaseInfo> purchases;\r
- String statusDescription;\r
- };\r
-\r
- using Callback = std::function<void(const Result&)>;\r
-\r
- GetProductsBoughtJob (Pimpl& parent,\r
- const LocalRef<jstring>& packageNameToUse,\r
- const Callback& callbackToUse)\r
- : ThreadPoolJob ("GetProductsBoughtJob"),\r
- owner (parent),\r
- packageName (LocalRef<jobject> (getEnv()->NewLocalRef (packageNameToUse.get()))),\r
- callback (callbackToUse)\r
- {}\r
-\r
- ThreadPoolJob::JobStatus runJob() override\r
- {\r
- jassert (callback);\r
-\r
- if (owner.checkIsReady())\r
- {\r
- auto inAppPurchases = getProductsBought ("inapp", 0);\r
- auto subsPurchases = getProductsBought ("subs", 0);\r
-\r
- inAppPurchases.addArray (subsPurchases);\r
-\r
- Array<InAppPurchases::Listener::PurchaseInfo> purchases;\r
-\r
- for (const auto& purchase : inAppPurchases)\r
- purchases.add ({ purchase, {} });\r
-\r
- if (callback)\r
- callback ({true, purchases, "Success"});\r
- }\r
- else\r
- {\r
- if (callback)\r
- callback ({false, {}, "In-App purchases unavailable"});\r
- }\r
-\r
- return jobHasFinished;\r
- }\r
-\r
- private:\r
- Array<InAppPurchases::Purchase> getProductsBought (const String& productType, jstring continuationToken)\r
- {\r
- Array<InAppPurchases::Purchase> purchases;\r
- auto* env = getEnv();\r
-\r
- auto productTypeString = javaString (productType);\r
- auto ownedItems = LocalRef<jobject> (owner.inAppBillingService.callObjectMethod (IInAppBillingService.getPurchases, 3,\r
- (jstring) packageName.get(), productTypeString.get(),\r
- continuationToken));\r
-\r
- if (ownedItems.get() != 0)\r
- {\r
- auto responseCodeString = javaString ("RESPONSE_CODE");\r
- auto responseCode = env->CallIntMethod (ownedItems.get(), AndroidBundle.getInt, responseCodeString.get());\r
-\r
- if (responseCode == 0)\r
- {\r
- auto itemListString = javaString ("INAPP_PURCHASE_ITEM_LIST");\r
- auto dataListString = javaString ("INAPP_PURCHASE_DATA_LIST");\r
- auto signatureListString = javaString ("INAPP_DATA_SIGNATURE_LIST");\r
- auto continuationTokenString = javaString ("INAPP_CONTINUATION_TOKEN");\r
+ owner.listeners.call ([&] (Listener& l) { l.productPurchaseFinished ({ purchase, {} }, success, statusDescription); });\r
+ }\r
\r
- auto ownedSkus = LocalRef<jobject> (env->CallObjectMethod (ownedItems.get(), AndroidBundle.getStringArrayList, itemListString.get()));\r
- auto purchaseDataList = LocalRef<jobject> (env->CallObjectMethod (ownedItems.get(), AndroidBundle.getStringArrayList, dataListString.get()));\r
- auto signatureList = LocalRef<jobject> (env->CallObjectMethod (ownedItems.get(), AndroidBundle.getStringArrayList, signatureListString.get()));\r
- auto newContinuationToken = LocalRef<jstring> ((jstring) env->CallObjectMethod (ownedItems.get(), AndroidBundle.getString, continuationTokenString.get()));\r
+ void notifyListenersAboutConsume (const String& productIdentifier, bool success, const String& statusDescription)\r
+ {\r
+ owner.listeners.call ([&] (Listener& l) { l.productConsumed (productIdentifier, success, statusDescription); });\r
+ }\r
\r
- for (auto i = 0; i < env->CallIntMethod (purchaseDataList.get(), JavaArrayList.size); ++i)\r
- {\r
- auto sku = juceString ((jstring) (env->CallObjectMethod (ownedSkus.get(), JavaArrayList.get, i)));\r
- auto purchaseData = juceString ((jstring) (env->CallObjectMethod (purchaseDataList.get(), JavaArrayList.get, i)));\r
- auto signature = juceString ((jstring) (env->CallObjectMethod (signatureList.get(), JavaArrayList.get, i)));\r
+ LocalRef<jobject> createBillingFlowParamsBuilder (LocalRef<jobject> skuDetails)\r
+ {\r
+ auto* env = getEnv();\r
\r
- var responseData = JSON::parse (purchaseData);\r
+ auto builder = LocalRef<jobject> (env->CallStaticObjectMethod (BillingFlowParams, BillingFlowParams.newBuilder));\r
\r
- if (auto* object = responseData.getDynamicObject())\r
- {\r
- auto& props = object->getProperties();\r
-\r
- static const Identifier orderIdIdentifier ("orderId"),\r
- packageNameIdentifier ("packageName"),\r
- productIdIdentifier ("productId"),\r
- purchaseTimeIdentifier ("purchaseTime"),\r
- purchaseTokenIdentifier ("purchaseToken");\r
-\r
- var orderId = props[orderIdIdentifier];\r
- var appPackageName = props[packageNameIdentifier];\r
- var productId = props[productIdIdentifier];\r
- var purchaseTime = props[purchaseTimeIdentifier];\r
- var purchaseToken = props[purchaseTokenIdentifier];\r
-\r
- String purchaseTimeString = Time (purchaseTime.toString().getLargeIntValue()).toString (true, true, true, true);\r
- purchases.add ({ orderId.toString(), productId.toString(), appPackageName.toString(), purchaseTimeString, purchaseToken.toString() });\r
- }\r
- }\r
+ return LocalRef<jobject> (env->CallObjectMethod (builder.get(),\r
+ BillingFlowParamsBuilder.setSkuDetails,\r
+ skuDetails.get()));\r
+ }\r
\r
- if (newContinuationToken.get() != 0)\r
- getProductsBought (productType, newContinuationToken.get());\r
- }\r
- }\r
+ void launchBillingFlowWithParameters (LocalRef<jobject> params)\r
+ {\r
+ LocalRef<jobject> activity (getCurrentActivity());\r
\r
- return purchases;\r
- }\r
+ if (activity == nullptr)\r
+ activity = getMainActivity();\r
\r
- Pimpl& owner;\r
- GlobalRef packageName;\r
- Callback callback;\r
- };\r
+ getEnv()->CallVoidMethod (billingClient,\r
+ JuceBillingClient.launchBillingFlow,\r
+ activity.get(),\r
+ params.get());\r
+ }\r
\r
- //==============================================================================\r
- class ConsumePurchaseJob : public ThreadPoolJob\r
+ void changeExistingSubscription (LocalRef<jobject> skuDetails, const String& subscriptionIdentifier, bool creditForUnusedSubscription)\r
{\r
- public:\r
- struct Result\r
- {\r
- bool success = false;\r
- String productIdentifier;\r
- String statusDescription;\r
- };\r
-\r
- using Callback = std::function<void(const Result&)>;\r
-\r
- ConsumePurchaseJob (Pimpl& parent,\r
- const LocalRef<jstring>& packageNameToUse,\r
- const String& productIdentifierToUse,\r
- const String& purchaseTokenToUse,\r
- const Callback& callbackToUse)\r
- : ThreadPoolJob ("ConsumePurchaseJob"),\r
- owner (parent),\r
- packageName (LocalRef<jobject> (getEnv()->NewLocalRef (packageNameToUse.get()))),\r
- productIdentifier (productIdentifierToUse),\r
- purchaseToken (purchaseTokenToUse),\r
- callback (callbackToUse)\r
- {}\r
-\r
- ThreadPoolJob::JobStatus runJob() override\r
+ if (! isReady())\r
{\r
- jassert (callback);\r
-\r
- if (owner.checkIsReady())\r
- {\r
- auto token = (! purchaseToken.isEmpty() ? purchaseToken : getPurchaseTokenForProductId (productIdentifier, false, 0));\r
-\r
- if (token.isEmpty())\r
- {\r
- if (callback)\r
- callback ({ false, productIdentifier, NEEDS_TRANS ("Item not owned") });\r
-\r
- return jobHasFinished;\r
- }\r
-\r
- auto responseCode = owner.inAppBillingService.callIntMethod (IInAppBillingService.consumePurchase, 3,\r
- (jstring)packageName.get(), javaString (token).get());\r
-\r
- if (callback)\r
- callback ({ responseCode == 0, productIdentifier, statusCodeToUserString (responseCode) });\r
- }\r
- else\r
- {\r
- if (callback)\r
- callback ({false, {}, "In-App purchases unavailable"});\r
- }\r
-\r
- return jobHasFinished;\r
+ notifyListenersAboutPurchase ({}, false, NEEDS_TRANS ("In-App purchases unavailable"));\r
+ return;\r
}\r
\r
- private:\r
- String getPurchaseTokenForProductId (const String productIdToLookFor, bool isSubscription, jstring continuationToken)\r
+ purchasesListQueryCallbackQueue.emplace ([=] (LocalRef<jobject> purchasesList)\r
{\r
- auto productTypeString = javaString (isSubscription ? "subs" : "inapp");\r
- auto ownedItems = LocalRef<jobject> (owner.inAppBillingService.callObjectMethod (IInAppBillingService.getPurchases, 3,\r
- (jstring) packageName.get(), productTypeString.get(),\r
- continuationToken));\r
-\r
- if (ownedItems.get() != 0)\r
+ if (purchasesList != nullptr)\r
{\r
auto* env = getEnv();\r
\r
- auto responseCodeString = javaString ("RESPONSE_CODE");\r
- auto responseCode = env->CallIntMethod (ownedItems.get(), AndroidBundle.getInt, responseCodeString.get());\r
-\r
- if (responseCode == 0)\r
+ for (int i = 0; i < env->CallIntMethod (purchasesList, JavaArrayList.size); ++i)\r
{\r
- auto dataListString = javaString ("INAPP_PURCHASE_DATA_LIST");\r
- auto continuationTokenString = javaString ("INAPP_CONTINUATION_TOKEN");\r
+ auto purchase = buildPurchase (LocalRef<jobject> (env->CallObjectMethod (purchasesList.get(), JavaArrayList.get, i)));\r
\r
- auto purchaseDataList = LocalRef<jobject> (env->CallObjectMethod (ownedItems.get(), AndroidBundle.getStringArrayList, dataListString.get()));\r
- auto newContinuationToken = LocalRef<jstring> ((jstring) env->CallObjectMethod (ownedItems.get(), AndroidBundle.getString, continuationTokenString.get()));\r
-\r
- for (auto i = 0; i < env->CallIntMethod (purchaseDataList.get(), JavaArrayList.size); ++i)\r
+ if (purchase.productId == subscriptionIdentifier)\r
{\r
- auto purchaseData = juceString ((jstring) (env->CallObjectMethod (purchaseDataList.get(), JavaArrayList.get, i)));\r
-\r
- var responseData = JSON::parse (purchaseData);\r
+ auto builder = createBillingFlowParamsBuilder (skuDetails);\r
\r
- if (auto* object = responseData.getDynamicObject())\r
- {\r
- static const Identifier productIdIdentifier ("productId"),\r
- purchaseTokenIdentifier ("purchaseToken");\r
+ builder = LocalRef<jobject> (env->CallObjectMethod (builder.get(),\r
+ BillingFlowParamsBuilder.setOldSku,\r
+ javaString (subscriptionIdentifier).get(),\r
+ javaString (purchase.purchaseToken).get()));\r
\r
- auto& props = object->getProperties();\r
- var productId = props[productIdIdentifier];\r
+ if (! creditForUnusedSubscription)\r
+ builder = LocalRef<jobject> (env->CallObjectMethod (builder.get(),\r
+ BillingFlowParamsBuilder.setReplaceSkusProrationMode,\r
+ 3 /*IMMEDIATE_WITHOUT_PRORATION*/));\r
\r
- if (productId.toString() == productIdToLookFor)\r
- return props[purchaseTokenIdentifier].toString();\r
- }\r
+ launchBillingFlowWithParameters (LocalRef<jobject> (env->CallObjectMethod (builder.get(),\r
+ BillingFlowParamsBuilder.build)));\r
}\r
-\r
- if (newContinuationToken.get() != 0)\r
- return getPurchaseTokenForProductId (productIdToLookFor, isSubscription, newContinuationToken.get());\r
}\r
}\r
\r
- return {};\r
- }\r
+ notifyListenersAboutPurchase ({}, false, NEEDS_TRANS ("Unable to get subscription details"));\r
+ });\r
\r
- Pimpl& owner;\r
- GlobalRef packageName;\r
- const String productIdentifier, purchaseToken;\r
- Callback callback;\r
- };\r
+ getProductsBoughtAsync();\r
+ }\r
\r
- //==============================================================================\r
- void handleAsyncUpdate() override\r
+ void purchaseProductWithSkuDetails (LocalRef<jobject> skuDetails)\r
{\r
+ if (! isReady())\r
{\r
- const ScopedLock lock (getProductsInformationJobResultsLock);\r
-\r
- for (int i = getProductsInformationJobResults.size(); --i >= 0;)\r
- {\r
- const auto& result = getProductsInformationJobResults.getReference (i);\r
-\r
- owner.listeners.call ([&] (Listener& l) { l.productsInfoReturned (result); });\r
- getProductsInformationJobResults.remove (i);\r
- }\r
+ notifyListenersAboutPurchase ({}, false, NEEDS_TRANS ("In-App purchases unavailable"));\r
+ return;\r
}\r
\r
- {\r
- const ScopedLock lock (getProductsBoughtJobResultsLock);\r
-\r
- for (int i = getProductsBoughtJobResults.size(); --i >= 0;)\r
- {\r
- const auto& result = getProductsBoughtJobResults.getReference (i);\r
-\r
- owner.listeners.call ([&] (Listener& l) { l.purchasesListRestored (result.purchases, result.success, result.statusDescription); });\r
- getProductsBoughtJobResults.remove (i);\r
- }\r
- }\r
+ launchBillingFlowWithParameters (LocalRef<jobject> (getEnv()->CallObjectMethod (createBillingFlowParamsBuilder (skuDetails).get(),\r
+ BillingFlowParamsBuilder.build)));\r
+ }\r
\r
+ void consumePurchaseWithToken (const String& productIdentifier, const String& purchaseToken)\r
+ {\r
+ if (! isReady())\r
{\r
- const ScopedLock lock (consumePurchaseJobResultsLock);\r
-\r
- for (int i = consumePurchaseJobResults.size(); --i >= 0;)\r
- {\r
- const auto& result = consumePurchaseJobResults.getReference (i);\r
-\r
- owner.listeners.call ([&] (Listener& l) { l.productConsumed (result.productIdentifier, result.success, result.statusDescription); });\r
- consumePurchaseJobResults.remove (i);\r
- }\r
+ notifyListenersAboutConsume (productIdentifier, false, NEEDS_TRANS ("In-App purchases unavailable"));\r
+ return;\r
}\r
+\r
+ getEnv()->CallObjectMethod (billingClient,\r
+ JuceBillingClient.consumePurchase,\r
+ LocalRef<jstring> (javaString (productIdentifier)).get(),\r
+ LocalRef<jstring> (javaString (purchaseToken)).get());\r
}\r
\r
//==============================================================================\r
- void inAppPurchaseCompleted (jobject intentData)\r
+ static InAppPurchases::Purchase buildPurchase (LocalRef<jobject> purchase)\r
{\r
+ if (purchase == nullptr)\r
+ return {};\r
+\r
auto* env = getEnv();\r
\r
- auto inAppPurchaseDataString = javaString ("INAPP_PURCHASE_DATA");\r
- auto inAppDataSignatureString = javaString ("INAPP_DATA_SIGNATURE");\r
- auto responseCodeString = javaString ("RESPONSE_CODE");\r
+ return { juceString (LocalRef<jstring> ((jstring) env->CallObjectMethod (purchase, AndroidPurchase.getOrderId))),\r
+ juceString (LocalRef<jstring> ((jstring) env->CallObjectMethod (purchase, AndroidPurchase.getSku))),\r
+ juceString (LocalRef<jstring> ((jstring) env->CallObjectMethod (purchase, AndroidPurchase.getPackageName))),\r
+ Time (env->CallLongMethod (purchase, AndroidPurchase.getPurchaseTime)).toString (true, true, true, true),\r
+ juceString (LocalRef<jstring> ((jstring) env->CallObjectMethod (purchase, AndroidPurchase.getPurchaseToken))) };\r
+ }\r
\r
- auto pd = LocalRef<jstring> ((jstring) env->CallObjectMethod (intentData, AndroidIntent.getStringExtra, inAppPurchaseDataString.get()));\r
- auto sig = LocalRef<jstring> ((jstring) env->CallObjectMethod (intentData, AndroidIntent.getStringExtra, inAppDataSignatureString.get()));\r
- auto purchaseDataString = pd.get() != 0 ? juceString (pd.get()) : String();\r
- auto dataSignatureString = sig.get() != 0 ? juceString (sig.get()) : String();\r
+ static InAppPurchases::Product buildProduct (LocalRef<jobject> productSkuDetails)\r
+ {\r
+ if (productSkuDetails == nullptr)\r
+ return {};\r
\r
- var responseData = JSON::parse (purchaseDataString);\r
+ auto* env = getEnv();\r
\r
- auto responseCode = env->CallIntMethod (intentData, AndroidIntent.getIntExtra, responseCodeString.get());\r
- auto statusCodeUserString = statusCodeToUserString (responseCode);\r
+ return { juceString (LocalRef<jstring> ((jstring) env->CallObjectMethod (productSkuDetails, SkuDetails.getSku))),\r
+ juceString (LocalRef<jstring> ((jstring) env->CallObjectMethod (productSkuDetails, SkuDetails.getTitle))),\r
+ juceString (LocalRef<jstring> ((jstring) env->CallObjectMethod (productSkuDetails, SkuDetails.getDescription))),\r
+ juceString (LocalRef<jstring> ((jstring) env->CallObjectMethod (productSkuDetails, SkuDetails.getPrice))),\r
+ juceString (LocalRef<jstring> ((jstring) env->CallObjectMethod (productSkuDetails, SkuDetails.getPriceCurrencyCode))) };\r
+ }\r
\r
- if (auto* object = responseData.getDynamicObject())\r
+ static String getStatusDescriptionFromResponseCode (int responseCode)\r
+ {\r
+ switch (responseCode)\r
{\r
- auto& props = object->getProperties();\r
-\r
- static const Identifier orderIdIdentifier ("orderId"),\r
- packageNameIdentifier ("packageName"),\r
- productIdIdentifier ("productId"),\r
- purchaseTimeIdentifier ("purchaseTime"),\r
- purchaseTokenIdentifier ("purchaseToken"),\r
- developerPayloadIdentifier ("developerPayload");\r
-\r
- var orderId = props[orderIdIdentifier];\r
- var packageName = props[packageNameIdentifier];\r
- var productId = props[productIdIdentifier];\r
- var purchaseTime = props[purchaseTimeIdentifier];\r
- var purchaseToken = props[purchaseTokenIdentifier];\r
- var developerPayload = props[developerPayloadIdentifier];\r
-\r
- auto purchaseTimeString = Time (purchaseTime.toString().getLargeIntValue())\r
- .toString (true, true, true, true);\r
-\r
- notifyAboutPurchaseResult ({ orderId.toString(), productId.toString(), packageName.toString(),\r
- purchaseTimeString, purchaseToken.toString() },\r
- true, statusCodeUserString);\r
- return;\r
+ case 0: return NEEDS_TRANS ("Success");\r
+ case 1: return NEEDS_TRANS ("Cancelled by user");\r
+ case 2: return NEEDS_TRANS ("Service unavailable");\r
+ case 3: return NEEDS_TRANS ("Billing unavailable");\r
+ case 4: return NEEDS_TRANS ("Item unavailable");\r
+ case 5: return NEEDS_TRANS ("Internal error");\r
+ case 6: return NEEDS_TRANS ("Generic error");\r
+ case 7: return NEEDS_TRANS ("Item already owned");\r
+ case 8: return NEEDS_TRANS ("Item not owned");\r
+ default: return NEEDS_TRANS ("Unknown status");\r
}\r
+ }\r
\r
- notifyAboutPurchaseResult ({}, false, statusCodeUserString);\r
+ static bool wasSuccessful (int responseCode)\r
+ {\r
+ return responseCode == 0;\r
}\r
\r
- //==============================================================================\r
- static String statusCodeToUserString (int statusCode)\r
+ void purchaseCompleted (jobject purchase, int responseCode)\r
{\r
- switch (statusCode)\r
- {\r
- case 0: return NEEDS_TRANS ("Success");\r
- case 1: return NEEDS_TRANS ("Cancelled by user");\r
- case 2: return NEEDS_TRANS ("Service unavailable");\r
- case 3: return NEEDS_TRANS ("Billing unavailable");\r
- case 4: return NEEDS_TRANS ("Item unavailable");\r
- case 5: return NEEDS_TRANS ("Internal error");\r
- case 6: return NEEDS_TRANS ("Generic error");\r
- case 7: return NEEDS_TRANS ("Item already owned");\r
- case 8: return NEEDS_TRANS ("Item not owned");\r
- default: jassertfalse; return NEEDS_TRANS ("Unknown status");\r
- }\r
+ notifyListenersAboutPurchase (buildPurchase (LocalRef<jobject> (purchase)),\r
+ wasSuccessful (responseCode),\r
+ getStatusDescriptionFromResponseCode (responseCode));\r
+ }\r
+\r
+ void purchaseConsumed (jstring productIdentifier, int responseCode)\r
+ {\r
+ notifyListenersAboutConsume (juceString (LocalRef<jstring> (productIdentifier)),\r
+ wasSuccessful (responseCode),\r
+ getStatusDescriptionFromResponseCode (responseCode));\r
+ }\r
+\r
+ void updateSkuDetails (jobject skuDetailsList)\r
+ {\r
+ jassert (! skuDetailsQueryCallbackQueue.empty());\r
+ skuDetailsQueryCallbackQueue.front() (LocalRef<jobject> (skuDetailsList));\r
+ skuDetailsQueryCallbackQueue.pop();\r
+ }\r
+\r
+ void updatePurchasesList (jobject purchasesList)\r
+ {\r
+ jassert (! purchasesListQueryCallbackQueue.empty());\r
+ purchasesListQueryCallbackQueue.front() (LocalRef<jobject> (purchasesList));\r
+ purchasesListQueryCallbackQueue.pop();\r
}\r
\r
//==============================================================================\r
InAppPurchases& owner;\r
- GlobalRef inAppBillingService, serviceConnection;\r
- std::unique_ptr<ThreadPool> threadPool;\r
+ GlobalRef billingClient;\r
\r
- CriticalSection getProductsInformationJobResultsLock,\r
- getProductsBoughtJobResultsLock,\r
- consumePurchaseJobResultsLock;\r
+ std::queue<std::function<void(LocalRef<jobject>)>> skuDetailsQueryCallbackQueue,\r
+ purchasesListQueryCallbackQueue;\r
\r
- Array<Array<InAppPurchases::Product>> getProductsInformationJobResults;\r
- Array<GetProductsBoughtJob::Result> getProductsBoughtJobResults;\r
- Array<ConsumePurchaseJob::Result> consumePurchaseJobResults;\r
+ //==============================================================================\r
+ JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Pimpl)\r
};\r
\r
\r
-//==============================================================================\r
-void juce_inAppPurchaseCompleted (void* intentData)\r
-{\r
- if (auto* instance = InAppPurchases::getInstance())\r
- instance->pimpl->inAppPurchaseCompleted (static_cast<jobject> (intentData));\r
-}\r
+InAppPurchases::Pimpl::JuceBillingClient_Class InAppPurchases::Pimpl::JuceBillingClient;\r
\r
} // namespace juce\r
[productsRequest start];\r
}\r
\r
- void purchaseProduct (const String& productIdentifier, bool, const StringArray&, bool)\r
+ void purchaseProduct (const String& productIdentifier, const String&, bool)\r
{\r
if (! [SKPaymentQueue canMakePayments])\r
{\r
\r
BEGIN_JUCE_MODULE_DECLARATION\r
\r
- ID: juce_video\r
- vendor: juce\r
- version: 5.4.5\r
- name: JUCE video playback and capture classes\r
- description: Classes for playing video and capturing camera input.\r
- website: http://www.juce.com/juce\r
- license: GPL/Commercial\r
-\r
- dependencies: juce_gui_extra\r
- OSXFrameworks: AVKit AVFoundation CoreMedia\r
- iOSFrameworks: AVKit AVFoundation CoreMedia\r
+ ID: juce_video\r
+ vendor: juce\r
+ version: 5.4.6\r
+ name: JUCE video playback and capture classes\r
+ description: Classes for playing video and capturing camera input.\r
+ website: http://www.juce.com/juce\r
+ license: GPL/Commercial\r
+\r
+ dependencies: juce_gui_extra\r
+ OSXFrameworks: AVKit AVFoundation CoreMedia\r
+ iOSFrameworks: AVKit AVFoundation CoreMedia\r
\r
END_JUCE_MODULE_DECLARATION\r
\r
\r
// When exception occurs, CameraCaptureSession.close will never finish, so\r
// we should not wait for it. For fatal error an exception does occur, but\r
- // it is catched internally in Java...\r
+ // it is caught internally in Java...\r
if (jniCheckHasExceptionOccurredAndClear() || scopedCameraDevice.fatalErrorOccurred.get())\r
{\r
JUCE_CAMERA_LOG ("Exception or fatal error occurred while closing Capture Session, closing by force");\r
\r
JUCE_CAMERA_LOG ("Available image codec types: " + typesString);\r
JUCE_CAMERA_LOG ("Still image stabilization supported: " + String ((int) stillImageOutput.stillImageStabilizationSupported));\r
- JUCE_CAMERA_LOG ("Automatically enableds still image stabilization when available: " + String ((int) stillImageOutput.automaticallyEnablesStillImageStabilizationWhenAvailable));\r
+ JUCE_CAMERA_LOG ("Automatically enables still image stabilization when available: " + String ((int) stillImageOutput.automaticallyEnablesStillImageStabilizationWhenAvailable));\r
\r
JUCE_CAMERA_LOG ("Output settings for image output: " + nsStringToJuce ([stillImageOutput.outputSettings description]));\r
}\r