Browse Source

Added support for building Unity native audio plugins on desktop platforms

tags/2021-05-28
ed 7 years ago
parent
commit
527625b699
32 changed files with 1599 additions and 53 deletions
  1. +2
    -2
      extras/Projucer/Builds/LinuxMakefile/Makefile
  2. +9
    -3
      extras/Projucer/Builds/MacOSX/Projucer.xcodeproj/project.pbxproj
  3. +3
    -2
      extras/Projucer/Builds/VisualStudio2013/Projucer_App.vcxproj
  4. +3
    -0
      extras/Projucer/Builds/VisualStudio2013/Projucer_App.vcxproj.filters
  5. +3
    -2
      extras/Projucer/Builds/VisualStudio2015/Projucer_App.vcxproj
  6. +3
    -0
      extras/Projucer/Builds/VisualStudio2015/Projucer_App.vcxproj.filters
  7. +3
    -2
      extras/Projucer/Builds/VisualStudio2017/Projucer_App.vcxproj
  8. +3
    -0
      extras/Projucer/Builds/VisualStudio2017/Projucer_App.vcxproj.filters
  9. +201
    -12
      extras/Projucer/JuceLibraryCode/BinaryData.cpp
  10. +4
    -1
      extras/Projucer/JuceLibraryCode/BinaryData.h
  11. +2
    -0
      extras/Projucer/Projucer.jucer
  12. +181
    -0
      extras/Projucer/Source/BinaryData/Templates/jucer_UnityPluginGUIScript.cs
  13. +8
    -2
      extras/Projucer/Source/Project/jucer_Project.cpp
  14. +10
    -0
      extras/Projucer/Source/Project/jucer_Project.h
  15. +2
    -0
      extras/Projucer/Source/Project/jucer_ProjectType.h
  16. +44
    -20
      extras/Projucer/Source/ProjectSaving/jucer_ProjectExport_MSVC.h
  17. +2
    -0
      extras/Projucer/Source/ProjectSaving/jucer_ProjectExport_Make.h
  18. +47
    -3
      extras/Projucer/Source/ProjectSaving/jucer_ProjectExport_Xcode.h
  19. +2
    -1
      extras/Projucer/Source/ProjectSaving/jucer_ProjectExporter.cpp
  20. +5
    -1
      extras/Projucer/Source/ProjectSaving/jucer_ProjectExporter.h
  21. +1
    -0
      extras/Projucer/Source/ProjectSaving/jucer_ProjectSaver.cpp
  22. +23
    -0
      extras/Projucer/Source/ProjectSaving/jucer_ProjectSaver.h
  23. +2
    -0
      extras/Projucer/Source/Utility/Helpers/jucer_PresetIDs.h
  24. +191
    -0
      modules/juce_audio_plugin_client/Unity/juce_UnityPluginInterface.h
  25. +779
    -0
      modules/juce_audio_plugin_client/Unity/juce_Unity_Wrapper.cpp
  26. +27
    -0
      modules/juce_audio_plugin_client/juce_audio_plugin_client_Unity.cpp
  27. +2
    -1
      modules/juce_audio_plugin_client/utility/juce_CheckSettingMacros.h
  28. +4
    -0
      modules/juce_audio_plugin_client/utility/juce_PluginUtilities.cpp
  29. +2
    -1
      modules/juce_audio_processors/processors/juce_AudioProcessor.h
  30. +19
    -0
      modules/juce_audio_processors/processors/juce_AudioProcessorEditor.cpp
  31. +2
    -0
      modules/juce_audio_processors/processors/juce_AudioProcessorEditor.h
  32. +10
    -0
      modules/juce_events/native/juce_win32_Messaging.cpp

+ 2
- 2
extras/Projucer/Builds/LinuxMakefile/Makefile View File

@@ -36,7 +36,7 @@ ifeq ($(CONFIG),Debug)
endif
JUCE_CPPFLAGS := $(DEPFLAGS) -DLINUX=1 -DDEBUG=1 -D_DEBUG=1 -DJUCER_LINUX_MAKE_6D53C8B4=1 -DJUCE_APP_VERSION=5.3.2 -DJUCE_APP_VERSION_HEX=0x50302 $(shell pkg-config --cflags freetype2 libcurl x11 xext xinerama 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
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_CFLAGS += $(JUCE_CPPFLAGS) $(TARGET_ARCH) -g -ggdb -O0 $(CFLAGS)
@@ -57,7 +57,7 @@ ifeq ($(CONFIG),Release)
endif
JUCE_CPPFLAGS := $(DEPFLAGS) -DLINUX=1 -DNDEBUG=1 -DJUCER_LINUX_MAKE_6D53C8B4=1 -DJUCE_APP_VERSION=5.3.2 -DJUCE_APP_VERSION_HEX=0x50302 $(shell pkg-config --cflags freetype2 libcurl x11 xext xinerama 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
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_CFLAGS += $(JUCE_CPPFLAGS) $(TARGET_ARCH) -O3 $(CFLAGS)


+ 9
- 3
extras/Projucer/Builds/MacOSX/Projucer.xcodeproj/project.pbxproj View File

@@ -233,6 +233,7 @@
72ED72174F9DBD0ABD8AFCED = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "jucer_PaintElementImage.cpp"; path = "../../Source/ComponentEditor/PaintElements/jucer_PaintElementImage.cpp"; sourceTree = "SOURCE_ROOT"; };
73DE14CEAD25D3445457013E = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "jucer_SliderHandler.h"; path = "../../Source/ComponentEditor/Components/jucer_SliderHandler.h"; sourceTree = "SOURCE_ROOT"; };
75BE2887C6F324B818D80A21 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "jucer_SnapGridPainter.h"; path = "../../Source/ComponentEditor/UI/jucer_SnapGridPainter.h"; sourceTree = "SOURCE_ROOT"; };
763A63E75AC802F17D11FE8B = {isa = PBXFileReference; lastKnownFileType = file.cs; name = "jucer_UnityPluginGUIScript.cs"; path = "../../Source/BinaryData/Templates/jucer_UnityPluginGUIScript.cs"; sourceTree = "SOURCE_ROOT"; };
7687A1374C60A025BDBE98DE = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "jucer_PointComponent.h"; path = "../../Source/ComponentEditor/PaintElements/jucer_PointComponent.h"; sourceTree = "SOURCE_ROOT"; };
77EA01E7D04BF889930BFF54 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "jucer_PaintElementRoundedRectangle.h"; path = "../../Source/ComponentEditor/PaintElements/jucer_PaintElementRoundedRectangle.h"; sourceTree = "SOURCE_ROOT"; };
78D0DBC4798FF040FDB90F6D = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "jucer_GeneratedCode.cpp"; path = "../../Source/ComponentEditor/jucer_GeneratedCode.cpp"; sourceTree = "SOURCE_ROOT"; };
@@ -493,7 +494,8 @@
3F7C5B53347A487C7FBD2223,
4ECF029E3A69BF42FED1503D,
3DC2ED15A9DFAAEF3D2ACDDF,
E67999BF57B139E00207A374, ); name = Templates; sourceTree = "<group>"; };
E67999BF57B139E00207A374,
763A63E75AC802F17D11FE8B, ); name = Templates; sourceTree = "<group>"; };
A9399733CAA07BDAB958242C = {isa = PBXGroup; children = (
8CF70DA9AB4725126B9F55BE,
F0F189518721D46C0F94FD56,
@@ -822,7 +824,8 @@
"JucePlugin_Build_AUv3=0",
"JucePlugin_Build_RTAS=0",
"JucePlugin_Build_AAX=0",
"JucePlugin_Build_Standalone=0", );
"JucePlugin_Build_Standalone=0",
"JucePlugin_Build_Unity=0", );
GCC_VERSION = com.apple.compilers.llvm.clang.1_0;
HEADER_SEARCH_PATHS = ("../../JuceLibraryCode", "../../../../modules", "$(inherited)");
INFOPLIST_FILE = Info-App.plist;
@@ -832,6 +835,7 @@
MACOSX_DEPLOYMENT_TARGET_ppc = 10.4;
OTHER_CPLUSPLUSFLAGS = "-Wall -Wshadow -Wno-missing-field-initializers -Wshadow -Wshorten-64-to-32 -Wstrict-aliasing -Wuninitialized -Wunused-parameter -Wconversion -Wsign-compare -Wint-conversion -Wconditional-uninitialized -Woverloaded-virtual -Wreorder -Wconstant-conversion -Wsign-conversion -Wunused-private-field -Wbool-conversion -Wextra-semi -Wno-ignored-qualifiers -Wunreachable-code";
PRODUCT_BUNDLE_IDENTIFIER = com.juce.theprojucer;
PRODUCT_NAME = "Projucer";
SDKROOT_ppc = macosx10.5;
USE_HEADERMAP = NO; }; name = Debug; };
0BC15DC2E5FE5ECFFB398D49 = {isa = XCBuildConfiguration; buildSettings = {
@@ -855,7 +859,8 @@
"JucePlugin_Build_AUv3=0",
"JucePlugin_Build_RTAS=0",
"JucePlugin_Build_AAX=0",
"JucePlugin_Build_Standalone=0", );
"JucePlugin_Build_Standalone=0",
"JucePlugin_Build_Unity=0", );
GCC_SYMBOLS_PRIVATE_EXTERN = YES;
GCC_VERSION = com.apple.compilers.llvm.clang.1_0;
HEADER_SEARCH_PATHS = ("../../JuceLibraryCode", "../../../../modules", "$(inherited)");
@@ -867,6 +872,7 @@
MACOSX_DEPLOYMENT_TARGET_ppc = 10.4;
OTHER_CPLUSPLUSFLAGS = "-Wall -Wshadow -Wno-missing-field-initializers -Wshadow -Wshorten-64-to-32 -Wstrict-aliasing -Wuninitialized -Wunused-parameter -Wconversion -Wsign-compare -Wint-conversion -Wconditional-uninitialized -Woverloaded-virtual -Wreorder -Wconstant-conversion -Wsign-conversion -Wunused-private-field -Wbool-conversion -Wextra-semi -Wno-ignored-qualifiers -Wunreachable-code";
PRODUCT_BUNDLE_IDENTIFIER = com.juce.theprojucer;
PRODUCT_NAME = "Projucer";
SDKROOT_ppc = macosx10.5;
USE_HEADERMAP = NO; }; name = Release; };
C42924A24AB55E6A940423EA = {isa = XCBuildConfiguration; buildSettings = {


+ 3
- 2
extras/Projucer/Builds/VisualStudio2013/Projucer_App.vcxproj View File

@@ -74,7 +74,7 @@
<Optimization>Disabled</Optimization>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<AdditionalIncludeDirectories>..\..\JuceLibraryCode;..\..\..\..\modules;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;DEBUG;_DEBUG;JUCER_VS2013_78A5020=1;JUCE_APP_VERSION=5.3.2;JUCE_APP_VERSION_HEX=0x50302;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;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;DEBUG;_DEBUG;JUCER_VS2013_78A5020=1;JUCE_APP_VERSION=5.3.2;JUCE_APP_VERSION_HEX=0x50302;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>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<RuntimeTypeInfo>true</RuntimeTypeInfo>
<PrecompiledHeader/>
@@ -115,7 +115,7 @@
<ClCompile>
<Optimization>Full</Optimization>
<AdditionalIncludeDirectories>..\..\JuceLibraryCode;..\..\..\..\modules;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;JUCER_VS2013_78A5020=1;JUCE_APP_VERSION=5.3.2;JUCE_APP_VERSION_HEX=0x50302;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;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;JUCER_VS2013_78A5020=1;JUCE_APP_VERSION=5.3.2;JUCE_APP_VERSION_HEX=0x50302;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>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<RuntimeTypeInfo>true</RuntimeTypeInfo>
<PrecompiledHeader/>
@@ -2065,6 +2065,7 @@
<None Include="..\..\Source\BinaryData\Icons\wizard_Openfile.svg"/>
<None Include="..\..\Source\BinaryData\Icons\wizard_OpenGL.svg"/>
<None Include="..\..\Source\BinaryData\Icons\wizard_StaticLibrary.svg"/>
<None Include="..\..\Source\BinaryData\Templates\jucer_UnityPluginGUIScript.cs"/>
<None Include="..\..\Source\BinaryData\colourscheme_dark.xml"/>
<None Include="..\..\Source\BinaryData\colourscheme_light.xml"/>
<None Include="..\..\Source\BinaryData\nothingtoseehere.txt"/>


+ 3
- 0
extras/Projucer/Builds/VisualStudio2013/Projucer_App.vcxproj.filters View File

@@ -3662,6 +3662,9 @@
<None Include="..\..\Source\BinaryData\Icons\wizard_StaticLibrary.svg">
<Filter>Projucer\BinaryData\Icons</Filter>
</None>
<None Include="..\..\Source\BinaryData\Templates\jucer_UnityPluginGUIScript.cs">
<Filter>Projucer\BinaryData\Templates</Filter>
</None>
<None Include="..\..\Source\BinaryData\colourscheme_dark.xml">
<Filter>Projucer\BinaryData</Filter>
</None>


+ 3
- 2
extras/Projucer/Builds/VisualStudio2015/Projucer_App.vcxproj View File

@@ -74,7 +74,7 @@
<Optimization>Disabled</Optimization>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<AdditionalIncludeDirectories>..\..\JuceLibraryCode;..\..\..\..\modules;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;DEBUG;_DEBUG;JUCER_VS2015_78A5022=1;JUCE_APP_VERSION=5.3.2;JUCE_APP_VERSION_HEX=0x50302;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;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;DEBUG;_DEBUG;JUCER_VS2015_78A5022=1;JUCE_APP_VERSION=5.3.2;JUCE_APP_VERSION_HEX=0x50302;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>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<RuntimeTypeInfo>true</RuntimeTypeInfo>
<PrecompiledHeader/>
@@ -115,7 +115,7 @@
<ClCompile>
<Optimization>Full</Optimization>
<AdditionalIncludeDirectories>..\..\JuceLibraryCode;..\..\..\..\modules;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;JUCER_VS2015_78A5022=1;JUCE_APP_VERSION=5.3.2;JUCE_APP_VERSION_HEX=0x50302;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;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;JUCER_VS2015_78A5022=1;JUCE_APP_VERSION=5.3.2;JUCE_APP_VERSION_HEX=0x50302;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>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<RuntimeTypeInfo>true</RuntimeTypeInfo>
<PrecompiledHeader/>
@@ -2065,6 +2065,7 @@
<None Include="..\..\Source\BinaryData\Icons\wizard_Openfile.svg"/>
<None Include="..\..\Source\BinaryData\Icons\wizard_OpenGL.svg"/>
<None Include="..\..\Source\BinaryData\Icons\wizard_StaticLibrary.svg"/>
<None Include="..\..\Source\BinaryData\Templates\jucer_UnityPluginGUIScript.cs"/>
<None Include="..\..\Source\BinaryData\colourscheme_dark.xml"/>
<None Include="..\..\Source\BinaryData\colourscheme_light.xml"/>
<None Include="..\..\Source\BinaryData\nothingtoseehere.txt"/>


+ 3
- 0
extras/Projucer/Builds/VisualStudio2015/Projucer_App.vcxproj.filters View File

@@ -3662,6 +3662,9 @@
<None Include="..\..\Source\BinaryData\Icons\wizard_StaticLibrary.svg">
<Filter>Projucer\BinaryData\Icons</Filter>
</None>
<None Include="..\..\Source\BinaryData\Templates\jucer_UnityPluginGUIScript.cs">
<Filter>Projucer\BinaryData\Templates</Filter>
</None>
<None Include="..\..\Source\BinaryData\colourscheme_dark.xml">
<Filter>Projucer\BinaryData</Filter>
</None>


+ 3
- 2
extras/Projucer/Builds/VisualStudio2017/Projucer_App.vcxproj View File

@@ -74,7 +74,7 @@
<Optimization>Disabled</Optimization>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<AdditionalIncludeDirectories>..\..\JuceLibraryCode;..\..\..\..\modules;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;DEBUG;_DEBUG;JUCER_VS2017_78A5024=1;JUCE_APP_VERSION=5.3.2;JUCE_APP_VERSION_HEX=0x50302;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;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;DEBUG;_DEBUG;JUCER_VS2017_78A5024=1;JUCE_APP_VERSION=5.3.2;JUCE_APP_VERSION_HEX=0x50302;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>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<RuntimeTypeInfo>true</RuntimeTypeInfo>
<PrecompiledHeader/>
@@ -115,7 +115,7 @@
<ClCompile>
<Optimization>Full</Optimization>
<AdditionalIncludeDirectories>..\..\JuceLibraryCode;..\..\..\..\modules;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;JUCER_VS2017_78A5024=1;JUCE_APP_VERSION=5.3.2;JUCE_APP_VERSION_HEX=0x50302;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;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;JUCER_VS2017_78A5024=1;JUCE_APP_VERSION=5.3.2;JUCE_APP_VERSION_HEX=0x50302;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>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<RuntimeTypeInfo>true</RuntimeTypeInfo>
<PrecompiledHeader/>
@@ -2065,6 +2065,7 @@
<None Include="..\..\Source\BinaryData\Icons\wizard_Openfile.svg"/>
<None Include="..\..\Source\BinaryData\Icons\wizard_OpenGL.svg"/>
<None Include="..\..\Source\BinaryData\Icons\wizard_StaticLibrary.svg"/>
<None Include="..\..\Source\BinaryData\Templates\jucer_UnityPluginGUIScript.cs"/>
<None Include="..\..\Source\BinaryData\colourscheme_dark.xml"/>
<None Include="..\..\Source\BinaryData\colourscheme_light.xml"/>
<None Include="..\..\Source\BinaryData\nothingtoseehere.txt"/>


+ 3
- 0
extras/Projucer/Builds/VisualStudio2017/Projucer_App.vcxproj.filters View File

@@ -3662,6 +3662,9 @@
<None Include="..\..\Source\BinaryData\Icons\wizard_StaticLibrary.svg">
<Filter>Projucer\BinaryData\Icons</Filter>
</None>
<None Include="..\..\Source\BinaryData\Templates\jucer_UnityPluginGUIScript.cs">
<Filter>Projucer\BinaryData\Templates</Filter>
</None>
<None Include="..\..\Source\BinaryData\colourscheme_dark.xml">
<Filter>Projucer\BinaryData</Filter>
</None>


+ 201
- 12
extras/Projucer/JuceLibraryCode/BinaryData.cpp View File

@@ -7267,8 +7267,194 @@ static const unsigned char temp_binary_data_54[] =
const char* jucer_PIPTemplate_h = (const char*) temp_binary_data_54;
//================== colourscheme_dark.xml ==================
//================== jucer_UnityPluginGUIScript.cs ==================
static const unsigned char temp_binary_data_55[] =
"#if UNITY_EDITOR\n"
"\n"
"using UnityEditor;\n"
"using UnityEngine;\n"
"\n"
"using System.Collections.Generic;\n"
"using System.Runtime.InteropServices;\n"
"\n"
"public class %%plugin_name%%GUI : IAudioEffectPluginGUI\n"
"{\n"
" public override string Name { get { return \"%%plugin_name%%\"; } }\n"
" public override string Description { get { return \"%%plugin_description%%\"; } }\n"
" public override string Vendor { get { return \"%%plugin_vendor%%\"; } }\n"
"\n"
" //==============================================================================\n"
"\t[DllImport(\"%%plugin_name%%\")] static extern System.IntPtr getRenderCallback();\n"
"\n"
" [DllImport(\"%%plugin_name%%\")] static extern void unityInitialiseTexture (int id, System.IntPtr texture, int width, int height);\n"
"\n"
" [DllImport(\"%%plugin_name%%\")] static extern void unityMouseDown (int id, float x, float y, EventModifiers mods, int button);\n"
" [DllImport(\"%%plugin_name%%\")] static extern void unityMouseDrag (int id, float x, float y, EventModifiers mods, int button);\n"
" [DllImport(\"%%plugin_name%%\")] static extern void unityMouseUp (int id, float x, float y, EventModifiers mods);\n"
"\n"
" [DllImport(\"%%plugin_name%%\")] static extern void unityKeyEvent (int id, KeyCode code, EventModifiers mods, string name);\n"
"\n"
" [DllImport(\"%%plugin_name%%\")] static extern void unitySetScreenBounds (int id, float x, float y, float w, float h);\n"
"\n"
" //==============================================================================\n"
" private class PluginGUIInstance\n"
" {\n"
" public PluginGUIInstance (ref IAudioEffectPlugin plugin, int id)\n"
" {\n"
" instanceID = id;\n"
"\n"
" float[] arr;\n"
" plugin.GetFloatBuffer (\"Editor\", out arr, 1);\n"
" hasEditor = (arr[0] > 0.0f);\n"
" }\n"
"\n"
" public void repaint (Rect r)\n"
" { \n"
" Vector2 newScreenPosition = GUIUtility.GUIToScreenPoint (r.position);\n"
"\n"
" if (bounds != r \n"
" || screenPosition != newScreenPosition)\n"
" {\n"
" screenPosition = newScreenPosition;\n"
" bounds = r;\n"
"\n"
" unitySetScreenBounds (instanceID, screenPosition.x, screenPosition.y, bounds.width, bounds.height);\n"
" setupTexture();\n"
" }\n"
"\n"
"\t\t\tGL.IssuePluginEvent (getRenderCallback(), instanceID);\n"
"\n"
" texture.SetPixels32 (pixels);\n"
" texture.Apply();\n"
"\n"
" EditorGUI.DrawPreviewTexture (bounds, texture);\n"
" }\n"
"\n"
" public bool handleMouseEvent (EventType eventType)\n"
" {\n"
" Vector2 mousePos = Event.current.mousePosition;\n"
" EventModifiers mods = Event.current.modifiers;\n"
"\n"
" if (! bounds.Contains (mousePos))\n"
" return false;\n"
"\n"
" Vector2 relativePos = new Vector2 (mousePos.x - bounds.x, mousePos.y - bounds.y);\n"
"\n"
" if (eventType == EventType.MouseDown) \n"
" {\n"
" unityMouseDown (instanceID, relativePos.x, relativePos.y, mods, Event.current.button);\n"
" GUIUtility.hotControl = GUIUtility.GetControlID (FocusType.Passive);\n"
" }\n"
" else if (eventType == EventType.MouseUp)\n"
" {\n"
" unityMouseUp (instanceID, relativePos.x, relativePos.y, mods);\n"
" GUIUtility.hotControl = 0;\n"
" }\n"
" else if (eventType == EventType.MouseDrag) \n"
" {\n"
" unityMouseDrag (instanceID, relativePos.x, relativePos.y, mods, Event.current.button);\n"
" }\n"
"\n"
" Event.current.Use();\n"
"\n"
" return true;\n"
" }\n"
"\n"
" public void handleKeyEvent (EventType eventType)\n"
" {\n"
" if (eventType == EventType.KeyDown)\n"
" {\n"
" KeyCode code = Event.current.keyCode;\n"
"\n"
" if (code == KeyCode.None)\n"
" return;\n"
"\n"
" EventModifiers mods = Event.current.modifiers;\n"
"\n"
" unityKeyEvent (instanceID, code, mods, code.ToString());\n"
" }\n"
" }\n"
"\n"
" private void setupTexture()\n"
" {\n"
" if (pixelHandle.IsAllocated)\n"
" pixelHandle.Free();\n"
"\n"
" texture = new Texture2D ((int) bounds.width, (int) bounds.height, TextureFormat.ARGB32, false);\n"
"\n"
" pixels = texture.GetPixels32();\n"
" pixelHandle = GCHandle.Alloc (pixels, GCHandleType.Pinned);\n"
"\n"
" unityInitialiseTexture (instanceID, pixelHandle.AddrOfPinnedObject(), texture.width, texture.height);\n"
" }\n"
"\n"
" public int instanceID = -1;\n"
" public bool hasEditor;\n"
"\n"
" private Vector2 screenPosition;\n"
" private Rect bounds;\n"
"\n"
" private Texture2D texture;\n"
" private Color32[] pixels;\n"
" private GCHandle pixelHandle;\n"
" }\n"
" List<PluginGUIInstance> guis = new List<PluginGUIInstance>();\n"
"\n"
" private PluginGUIInstance getGUIInstanceForPlugin (ref IAudioEffectPlugin plugin)\n"
" {\n"
" float[] idArray;\n"
" plugin.GetFloatBuffer (\"ID\", out idArray, 1);\n"
"\n"
" int id = (int) idArray[0];\n"
"\n"
" for (int i = 0; i < guis.Count; ++i)\n"
" {\n"
" if (guis[i].instanceID == id)\n"
" return guis[i];\n"
" }\n"
"\n"
" PluginGUIInstance newInstance = new PluginGUIInstance (ref plugin, id);\n"
" guis.Add (newInstance);\n"
"\n"
" return guis[guis.Count - 1];\n"
" }\n"
"\n"
" //==============================================================================\n"
" public override bool OnGUI (IAudioEffectPlugin plugin)\n"
" {\n"
" PluginGUIInstance guiInstance = getGUIInstanceForPlugin (ref plugin);\n"
"\n"
" if (! guiInstance.hasEditor)\n"
" return true;\n"
"\n"
" float[] arr;\n"
" plugin.GetFloatBuffer (\"Size\", out arr, 6);\n"
"\n"
" Rect r = GUILayoutUtility.GetRect (arr[0], arr[1],\n"
" new GUILayoutOption[] { GUILayout.MinWidth (arr[2]), GUILayout.MinHeight (arr[3]),\n"
" GUILayout.MaxWidth (arr[4]), GUILayout.MaxHeight (arr[5]) });\n"
"\n"
" int controlID = GUIUtility.GetControlID (FocusType.Passive);\n"
" Event currentEvent = Event.current;\n"
" EventType currentEventType = currentEvent.GetTypeForControl (controlID);\n"
"\n"
" if (currentEventType == EventType.Repaint)\n"
" guiInstance.repaint (r);\n"
" else if (currentEvent.isMouse)\n"
" guiInstance.handleMouseEvent (currentEventType);\n"
" else if (currentEvent.isKey)\n"
" guiInstance.handleKeyEvent (currentEventType);\n"
"\n"
" return false;\n"
" }\n"
"}\n"
"\n"
"#endif";
const char* jucer_UnityPluginGUIScript_cs = (const char*) temp_binary_data_55;
//================== colourscheme_dark.xml ==================
static const unsigned char temp_binary_data_56[] =
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n"
"\r\n"
"<COLOUR_SCHEME font=\"&lt;Monospaced&gt;; 13.0\">\r\n"
@@ -7293,10 +7479,10 @@ static const unsigned char temp_binary_data_55[] =
" <COLOUR name=\"Error\" colour=\"FFE60000\"/>\r\n"
"</COLOUR_SCHEME>\r\n";
const char* colourscheme_dark_xml = (const char*) temp_binary_data_55;
const char* colourscheme_dark_xml = (const char*) temp_binary_data_56;
//================== colourscheme_light.xml ==================
static const unsigned char temp_binary_data_56[] =
static const unsigned char temp_binary_data_57[] =
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n"
"\r\n"
"<COLOUR_SCHEME font=\"&lt;Monospaced&gt;; 13.0\">\r\n"
@@ -7321,16 +7507,16 @@ static const unsigned char temp_binary_data_56[] =
" <COLOUR name=\"Error\" colour=\"ffcc0000\"/>\r\n"
"</COLOUR_SCHEME>\r\n";
const char* colourscheme_light_xml = (const char*) temp_binary_data_56;
const char* colourscheme_light_xml = (const char*) temp_binary_data_57;
//================== nothingtoseehere.txt ==================
static const unsigned char temp_binary_data_57[] =
static const unsigned char temp_binary_data_58[] =
"VUEtMTk3NTkzMTgtNA==";
const char* nothingtoseehere_txt = (const char*) temp_binary_data_57;
const char* nothingtoseehere_txt = (const char*) temp_binary_data_58;
//================== offlinepage.html ==================
static const unsigned char temp_binary_data_58[] =
static const unsigned char temp_binary_data_59[] =
"<html>\n"
" <head>\n"
" <meta http-equiv=\"X-UA-Compatible\" content=\"IE=11\">\n"
@@ -7374,10 +7560,10 @@ static const unsigned char temp_binary_data_58[] =
" </body>\n"
"</html>";
const char* offlinepage_html = (const char*) temp_binary_data_58;
const char* offlinepage_html = (const char*) temp_binary_data_59;
//================== projucer_EULA.txt ==================
static const unsigned char temp_binary_data_59[] =
static const unsigned char temp_binary_data_60[] =
"\r\n"
"IMPORTANT NOTICE: PLEASE READ CAREFULLY BEFORE INSTALLING THE SOFTWARE:\r\n"
"\r\n"
@@ -7541,10 +7727,10 @@ static const unsigned char temp_binary_data_59[] =
"\r\n"
"10.6. Please note that this License, its subject matter and its formation, are governed by English law. You and we both agree to that the courts of England and Wales will have exclusive jurisdiction.\r\n";
const char* projucer_EULA_txt = (const char*) temp_binary_data_59;
const char* projucer_EULA_txt = (const char*) temp_binary_data_60;
//================== RecentFilesMenuTemplate.nib ==================
static const unsigned char temp_binary_data_60[] =
static const unsigned char temp_binary_data_61[] =
{ 98,112,108,105,115,116,48,48,212,0,1,0,2,0,3,0,4,0,5,0,6,1,53,1,54,88,36,118,101,114,115,105,111,110,88,36,111,98,106,101,99,116,115,89,36,97,114,99,104,105,118,101,114,84,36,116,111,112,18,0,1,134,160,175,16,74,0,7,0,8,0,31,0,35,0,36,0,42,0,46,0,50,
0,53,0,57,0,74,0,77,0,78,0,86,0,87,0,97,0,112,0,113,0,114,0,119,0,120,0,121,0,124,0,128,0,129,0,132,0,143,0,144,0,145,0,149,0,153,0,162,0,163,0,164,0,169,0,173,0,180,0,181,0,182,0,185,0,192,0,193,0,200,0,201,0,208,0,209,0,216,0,217,0,224,0,225,0,226,
0,229,0,230,0,232,0,249,1,11,1,29,1,30,1,31,1,32,1,33,1,34,1,35,1,36,1,37,1,38,1,39,1,40,1,41,1,42,1,43,1,44,1,47,1,50,85,36,110,117,108,108,219,0,9,0,10,0,11,0,12,0,13,0,14,0,15,0,16,0,17,0,18,0,19,0,20,0,21,0,22,0,23,0,24,0,25,0,26,0,27,0,28,0,29,0,
@@ -7581,7 +7767,7 @@ static const unsigned char temp_binary_data_60[] =
7,157,7,159,7,161,7,163,7,165,7,167,7,169,7,171,7,173,7,175,7,177,7,179,7,181,7,190,7,192,7,225,7,227,7,229,7,231,7,233,7,235,7,237,7,239,7,241,7,243,7,245,7,247,7,249,7,251,7,253,7,255,8,2,8,5,8,8,8,11,8,14,8,17,8,20,8,23,8,26,8,29,8,32,8,35,8,38,8,
41,8,44,8,53,8,55,8,56,8,65,8,67,8,68,8,77,8,92,8,97,8,115,8,120,8,134,0,0,0,0,0,0,2,2,0,0,0,0,0,0,1,57,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,136,0,0 };
const char* RecentFilesMenuTemplate_nib = (const char*) temp_binary_data_60;
const char* RecentFilesMenuTemplate_nib = (const char*) temp_binary_data_61;
const char* getNamedResource (const char* resourceNameUTF8, int& numBytes)
@@ -7648,6 +7834,7 @@ const char* getNamedResource (const char* resourceNameUTF8, int& numBytes)
case 0xbc050edc: numBytes = 4926; return jucer_PIPAudioProcessorTemplate_h;
case 0xf4ca9e9a: numBytes = 2447; return jucer_PIPMain_cpp;
case 0x0b16e320: numBytes = 517; return jucer_PIPTemplate_h;
case 0xcd472557: numBytes = 6426; return jucer_UnityPluginGUIScript_cs;
case 0x763d39dc: numBytes = 1050; return colourscheme_dark_xml;
case 0xe8b08520: numBytes = 1050; return colourscheme_light_xml;
case 0x938e96ec: numBytes = 20; return nothingtoseehere_txt;
@@ -7718,6 +7905,7 @@ const char* namedResourceList[] =
"jucer_PIPAudioProcessorTemplate_h",
"jucer_PIPMain_cpp",
"jucer_PIPTemplate_h",
"jucer_UnityPluginGUIScript_cs",
"colourscheme_dark_xml",
"colourscheme_light_xml",
"nothingtoseehere_txt",
@@ -7783,6 +7971,7 @@ const char* originalFilenames[] =
"jucer_PIPAudioProcessorTemplate.h",
"jucer_PIPMain.cpp",
"jucer_PIPTemplate.h",
"jucer_UnityPluginGUIScript.cs",
"colourscheme_dark.xml",
"colourscheme_light.xml",
"nothingtoseehere.txt",


+ 4
- 1
extras/Projucer/JuceLibraryCode/BinaryData.h View File

@@ -173,6 +173,9 @@ namespace BinaryData
extern const char* jucer_PIPTemplate_h;
const int jucer_PIPTemplate_hSize = 517;
extern const char* jucer_UnityPluginGUIScript_cs;
const int jucer_UnityPluginGUIScript_csSize = 6426;
extern const char* colourscheme_dark_xml;
const int colourscheme_dark_xmlSize = 1050;
@@ -192,7 +195,7 @@ namespace BinaryData
const int RecentFilesMenuTemplate_nibSize = 2842;
// Number of elements in the namedResourceList and originalFileNames arrays.
const int namedResourceListSize = 61;
const int namedResourceListSize = 62;
// Points to the start of a list of resource names.
extern const char* namedResourceList[];


+ 2
- 0
extras/Projucer/Projucer.jucer View File

@@ -263,6 +263,8 @@
file="Source/BinaryData/Templates/jucer_PIPMain.cpp"/>
<FILE id="WqDCf0" name="jucer_PIPTemplate.h" compile="0" resource="1"
file="Source/BinaryData/Templates/jucer_PIPTemplate.h"/>
<FILE id="wrkU1v" name="jucer_UnityPluginGUIScript.cs" compile="0"
resource="1" file="Source/BinaryData/Templates/jucer_UnityPluginGUIScript.cs"/>
</GROUP>
<FILE id="oXM3fR" name="colourscheme_dark.xml" compile="0" resource="1"
file="Source/BinaryData/colourscheme_dark.xml"/>


+ 181
- 0
extras/Projucer/Source/BinaryData/Templates/jucer_UnityPluginGUIScript.cs View File

@@ -0,0 +1,181 @@
#if UNITY_EDITOR

using UnityEditor;
using UnityEngine;

using System.Collections.Generic;
using System.Runtime.InteropServices;

public class %%plugin_name%%GUI : IAudioEffectPluginGUI
{
public override string Name { get { return "%%plugin_name%%"; } }
public override string Description { get { return "%%plugin_description%%"; } }
public override string Vendor { get { return "%%plugin_vendor%%"; } }

//==============================================================================
[DllImport("%%plugin_name%%")] static extern System.IntPtr getRenderCallback();

[DllImport("%%plugin_name%%")] static extern void unityInitialiseTexture (int id, System.IntPtr texture, int width, int height);

[DllImport("%%plugin_name%%")] static extern void unityMouseDown (int id, float x, float y, EventModifiers mods, int button);
[DllImport("%%plugin_name%%")] static extern void unityMouseDrag (int id, float x, float y, EventModifiers mods, int button);
[DllImport("%%plugin_name%%")] static extern void unityMouseUp (int id, float x, float y, EventModifiers mods);

[DllImport("%%plugin_name%%")] static extern void unityKeyEvent (int id, KeyCode code, EventModifiers mods, string name);

[DllImport("%%plugin_name%%")] static extern void unitySetScreenBounds (int id, float x, float y, float w, float h);

//==============================================================================
private class PluginGUIInstance
{
public PluginGUIInstance (ref IAudioEffectPlugin plugin, int id)
{
instanceID = id;

float[] arr;
plugin.GetFloatBuffer ("Editor", out arr, 1);
hasEditor = (arr[0] > 0.0f);
}

public void repaint (Rect r)
{
Vector2 newScreenPosition = GUIUtility.GUIToScreenPoint (r.position);

if (bounds != r
|| screenPosition != newScreenPosition)
{
screenPosition = newScreenPosition;
bounds = r;

unitySetScreenBounds (instanceID, screenPosition.x, screenPosition.y, bounds.width, bounds.height);
setupTexture();
}

GL.IssuePluginEvent (getRenderCallback(), instanceID);

texture.SetPixels32 (pixels);
texture.Apply();

EditorGUI.DrawPreviewTexture (bounds, texture);
}

public bool handleMouseEvent (EventType eventType)
{
Vector2 mousePos = Event.current.mousePosition;
EventModifiers mods = Event.current.modifiers;

if (! bounds.Contains (mousePos))
return false;

Vector2 relativePos = new Vector2 (mousePos.x - bounds.x, mousePos.y - bounds.y);

if (eventType == EventType.MouseDown)
{
unityMouseDown (instanceID, relativePos.x, relativePos.y, mods, Event.current.button);
GUIUtility.hotControl = GUIUtility.GetControlID (FocusType.Passive);
}
else if (eventType == EventType.MouseUp)
{
unityMouseUp (instanceID, relativePos.x, relativePos.y, mods);
GUIUtility.hotControl = 0;
}
else if (eventType == EventType.MouseDrag)
{
unityMouseDrag (instanceID, relativePos.x, relativePos.y, mods, Event.current.button);
}

Event.current.Use();

return true;
}

public void handleKeyEvent (EventType eventType)
{
if (eventType == EventType.KeyDown)
{
KeyCode code = Event.current.keyCode;

if (code == KeyCode.None)
return;

EventModifiers mods = Event.current.modifiers;

unityKeyEvent (instanceID, code, mods, code.ToString());
}
}

private void setupTexture()
{
if (pixelHandle.IsAllocated)
pixelHandle.Free();

texture = new Texture2D ((int) bounds.width, (int) bounds.height, TextureFormat.ARGB32, false);

pixels = texture.GetPixels32();
pixelHandle = GCHandle.Alloc (pixels, GCHandleType.Pinned);

unityInitialiseTexture (instanceID, pixelHandle.AddrOfPinnedObject(), texture.width, texture.height);
}

public int instanceID = -1;
public bool hasEditor;

private Vector2 screenPosition;
private Rect bounds;

private Texture2D texture;
private Color32[] pixels;
private GCHandle pixelHandle;
}
List<PluginGUIInstance> guis = new List<PluginGUIInstance>();

private PluginGUIInstance getGUIInstanceForPlugin (ref IAudioEffectPlugin plugin)
{
float[] idArray;
plugin.GetFloatBuffer ("ID", out idArray, 1);

int id = (int) idArray[0];

for (int i = 0; i < guis.Count; ++i)
{
if (guis[i].instanceID == id)
return guis[i];
}

PluginGUIInstance newInstance = new PluginGUIInstance (ref plugin, id);
guis.Add (newInstance);

return guis[guis.Count - 1];
}

//==============================================================================
public override bool OnGUI (IAudioEffectPlugin plugin)
{
PluginGUIInstance guiInstance = getGUIInstanceForPlugin (ref plugin);

if (! guiInstance.hasEditor)
return true;

float[] arr;
plugin.GetFloatBuffer ("Size", out arr, 6);

Rect r = GUILayoutUtility.GetRect (arr[0], arr[1],
new GUILayoutOption[] { GUILayout.MinWidth (arr[2]), GUILayout.MinHeight (arr[3]),
GUILayout.MaxWidth (arr[4]), GUILayout.MaxHeight (arr[5]) });

int controlID = GUIUtility.GetControlID (FocusType.Passive);
Event currentEvent = Event.current;
EventType currentEventType = currentEvent.GetTypeForControl (controlID);

if (currentEventType == EventType.Repaint)
guiInstance.repaint (r);
else if (currentEvent.isMouse)
guiInstance.handleMouseEvent (currentEventType);
else if (currentEvent.isKey)
guiInstance.handleKeyEvent (currentEventType);

return false;
}
}

#endif

+ 8
- 2
extras/Projucer/Source/Project/jucer_Project.cpp View File

@@ -822,6 +822,8 @@ bool Project::shouldBuildTargetType (ProjectType::Target::Type targetType) const
return shouldBuildAUv3();
case ProjectType::Target::StandalonePlugIn:
return shouldBuildStandalonePlugin();
case ProjectType::Target::UnityPlugIn:
return shouldBuildUnityPlugin();
case ProjectType::Target::AggregateTarget:
case ProjectType::Target::SharedCodeTarget:
return projectType.isAudioPlugin();
@@ -843,6 +845,7 @@ ProjectType::Target::Type Project::getTargetTypeFromFilePath (const File& file,
else if (LibraryModule::CompileUnit::hasSuffix (file, "_VST2")) return ProjectType::Target::VSTPlugIn;
else if (LibraryModule::CompileUnit::hasSuffix (file, "_VST3")) return ProjectType::Target::VST3PlugIn;
else if (LibraryModule::CompileUnit::hasSuffix (file, "_Standalone")) return ProjectType::Target::StandalonePlugIn;
else if (LibraryModule::CompileUnit::hasSuffix (file, "_Unity")) return ProjectType::Target::UnityPlugIn;
return (returnSharedTargetIfNoValidSuffix ? ProjectType::Target::SharedCodeTarget : ProjectType::Target::unspecified);
}
@@ -862,6 +865,7 @@ const char* ProjectType::Target::getName() const noexcept
case AudioUnitv3PlugIn: return "AUv3 AppExtension";
case AAXPlugIn: return "AAX";
case RTASPlugIn: return "RTAS";
case UnityPlugIn: return "Unity Plugin";
case SharedCodeTarget: return "Shared Code";
case AggregateTarget: return "All";
default: return "undefined";
@@ -883,6 +887,7 @@ ProjectType::Target::TargetFileType ProjectType::Target::getTargetFileType() con
case AudioUnitv3PlugIn: return macOSAppex;
case AAXPlugIn: return pluginBundle;
case RTASPlugIn: return pluginBundle;
case UnityPlugIn: return pluginBundle;
case SharedCodeTarget: return staticLibrary;
default:
break;
@@ -1016,9 +1021,10 @@ void Project::createPropertyEditors (PropertyListBuilder& props)
void Project::createAudioPluginPropertyEditors (PropertyListBuilder& props)
{
props.add (new MultiChoicePropertyComponent (pluginFormatsValue, "Plugin Formats",
{ "VST", "VST3", "AU", "AUv3", "RTAS", "AAX", "Standalone", "Enable IAA" },
{ "VST", "VST3", "AU", "AUv3", "RTAS", "AAX", "Standalone", "Unity", "Enable IAA" },
{ Ids::buildVST.toString(), Ids::buildVST3.toString(), Ids::buildAU.toString(), Ids::buildAUv3.toString(),
Ids::buildRTAS.toString(), Ids::buildAAX.toString(), Ids::buildStandalone.toString(), Ids::enableIAA.toString() }),
Ids::buildRTAS.toString(), Ids::buildAAX.toString(), Ids::buildStandalone.toString(), Ids::buildUnity.toString(),
Ids::enableIAA.toString() }),
"Plugin formats to build.");
props.add (new MultiChoicePropertyComponent (pluginCharacteristicsValue, "Plugin Characteristics",
{ "Plugin is a Synth", "Plugin MIDI Input", "Plugin MIDI Output", "MIDI Effect Plugin", "Plugin Editor Requires Keyboard Focus",


+ 10
- 0
extras/Projucer/Source/Project/jucer_Project.h View File

@@ -158,6 +158,7 @@ public:
bool shouldBuildRTAS() const { return checkMultiChoiceVar (pluginFormatsValue, Ids::buildRTAS); }
bool shouldBuildAAX() const { return checkMultiChoiceVar (pluginFormatsValue, Ids::buildAAX); }
bool shouldBuildStandalonePlugin() const { return checkMultiChoiceVar (pluginFormatsValue, Ids::buildStandalone); }
bool shouldBuildUnityPlugin() const { return checkMultiChoiceVar (pluginFormatsValue, Ids::buildUnity); }
bool shouldEnableIAA() const { return checkMultiChoiceVar (pluginFormatsValue, Ids::enableIAA); }
//==============================================================================
@@ -199,6 +200,15 @@ public:
String getIAATypeCode();
String getIAAPluginName();
String getUnityScriptName() const { return addUnityPluginPrefixIfNecessary (getProjectNameString()) + "_UnityScript.cs"; }
static String addUnityPluginPrefixIfNecessary (const String& name)
{
if (! name.startsWithIgnoreCase ("audioplugin"))
return "audioplugin_" + name;
return name;
}
//==============================================================================
bool isAUPluginHost();
bool isVSTPluginHost();


+ 2
- 0
extras/Projucer/Source/Project/jucer_ProjectType.h View File

@@ -67,6 +67,7 @@ public:
AudioUnitPlugIn = 14,
AudioUnitv3PlugIn = 15,
StandalonePlugIn = 16,
UnityPlugIn = 17,
SharedCodeTarget = 20, // internal
AggregateTarget = 21,
@@ -186,6 +187,7 @@ struct ProjectType_AudioPlugin : public ProjectType
case Target::AudioUnitPlugIn:
case Target::AudioUnitv3PlugIn:
case Target::StandalonePlugIn:
case Target::UnityPlugIn:
case Target::SharedCodeTarget:
case Target::AggregateTarget:
return true;


+ 44
- 20
extras/Projucer/Source/ProjectSaving/jucer_ProjectExport_MSVC.h View File

@@ -158,7 +158,8 @@ public:
vstBinaryLocation (config, Ids::vstBinaryLocation, getUndoManager()),
vst3BinaryLocation (config, Ids::vst3BinaryLocation, getUndoManager()),
rtasBinaryLocation (config, Ids::rtasBinaryLocation, getUndoManager()),
aaxBinaryLocation (config, Ids::aaxBinaryLocation, getUndoManager())
aaxBinaryLocation (config, Ids::aaxBinaryLocation, getUndoManager()),
unityPluginBinaryLocation (config, Ids::unityPluginBinaryLocation, getUndoManager(), {})
{
if (! isDebug())
updateOldLTOSetting();
@@ -203,6 +204,7 @@ public:
String getVST3BinaryLocationString() const { return vst3BinaryLocation.get(); }
String getRTASBinaryLocationString() const { return rtasBinaryLocation.get();}
String getAAXBinaryLocationString() const { return aaxBinaryLocation.get();}
String getUnityPluginBinaryLocationString() const { return unityPluginBinaryLocation.get(); }
//==============================================================================
String createMSVCConfigName() const
@@ -210,9 +212,9 @@ public:
return getName() + "|" + (is64Bit() ? "x64" : "Win32");
}
String getOutputFilename (const String& suffix, bool forceSuffix) const
String getOutputFilename (const String& suffix, bool forceSuffix, bool forceUnityPrefix) const
{
auto target = File::createLegalFileName (getTargetBinaryNameString().trim());
auto target = File::createLegalFileName (getTargetBinaryNameString (forceUnityPrefix).trim());
if (forceSuffix || ! target.containsChar ('.'))
return target.upToLastOccurrenceOf (".", false, false) + suffix;
@@ -308,7 +310,7 @@ public:
generateManifestValue, enableIncrementalLinkingValue, useRuntimeLibDLLValue, intermediatesPathValue,
characterSetValue, architectureTypeValue, fastMathValue, debugInformationFormatValue, pluginBinaryCopyStepValue;
ValueWithDefault vstBinaryLocation, vst3BinaryLocation, rtasBinaryLocation, aaxBinaryLocation;
ValueWithDefault vstBinaryLocation, vst3BinaryLocation, rtasBinaryLocation, aaxBinaryLocation, unityPluginBinaryLocation;
Value architectureValueToListenTo;
@@ -321,8 +323,8 @@ public:
void addVisualStudioPluginInstallPathProperties (PropertyListBuilder& props)
{
auto isBuildingAnyPlugins = (project.shouldBuildVST() || project.shouldBuildVST3()
|| project.shouldBuildRTAS() || project.shouldBuildAAX());
auto isBuildingAnyPlugins = (project.shouldBuildVST() || project.shouldBuildVST3() || project.shouldBuildRTAS()
|| project.shouldBuildAAX() || project.shouldBuildUnityPlugin());
if (isBuildingAnyPlugins)
props.add (new ChoicePropertyComponent (pluginBinaryCopyStepValue, "Enable Plugin Copy Step"),
@@ -348,6 +350,11 @@ public:
1024, false),
"The folder in which the compiled AAX binary should be placed.");
if (project.shouldBuildUnityPlugin())
props.add (new TextPropertyComponentWithEnablement (unityPluginBinaryLocation, pluginBinaryCopyStepValue, "Unity Binary Location",
1024, false),
"The folder in which the compiled Unity plugin binary and associated C# GUI script should be placed.");
}
void setPluginBinaryCopyLocationDefaults()
@@ -497,7 +504,7 @@ public:
{
auto* targetName = props->createNewChildElement ("TargetName");
setConditionAttribute (*targetName, config);
targetName->addTextElement (config.getOutputFilename ("", false));
targetName->addTextElement (config.getOutputFilename ("", false, type == UnityPlugIn));
}
{
@@ -608,12 +615,12 @@ public:
{
auto* link = group->createNewChildElement ("Link");
link->createNewChildElement ("OutputFile")->addTextElement (getOutputFilePath (config));
link->createNewChildElement ("OutputFile")->addTextElement (getOutputFilePath (config, type == UnityPlugIn));
link->createNewChildElement ("SuppressStartupBanner")->addTextElement ("true");
link->createNewChildElement ("IgnoreSpecificDefaultLibraries")->addTextElement (isDebug ? "libcmt.lib; msvcrt.lib;;%(IgnoreSpecificDefaultLibraries)"
: "%(IgnoreSpecificDefaultLibraries)");
link->createNewChildElement ("GenerateDebugInformation")->addTextElement ((isDebug || config.shouldGenerateDebugSymbols()) ? "true" : "false");
link->createNewChildElement ("ProgramDatabaseFile")->addTextElement (getOwner().getIntDirFile (config, config.getOutputFilename (".pdb", true)));
link->createNewChildElement ("ProgramDatabaseFile")->addTextElement (getOwner().getIntDirFile (config, config.getOutputFilename (".pdb", true, type == UnityPlugIn)));
link->createNewChildElement ("SubSystem")->addTextElement (type == ConsoleApp ? "Console" : "Windows");
if (! config.is64Bit())
@@ -654,7 +661,7 @@ public:
{
auto* bsc = group->createNewChildElement ("Bscmake");
bsc->createNewChildElement ("SuppressStartupBanner")->addTextElement ("true");
bsc->createNewChildElement ("OutputFile")->addTextElement (getOwner().getIntDirFile (config, config.getOutputFilename (".bsc", true)));
bsc->createNewChildElement ("OutputFile")->addTextElement (getOwner().getIntDirFile (config, config.getOutputFilename (".bsc", true, type == UnityPlugIn)));
}
if (type != SharedCodeTarget)
@@ -1078,13 +1085,13 @@ public:
RelativePath bundleScript = aaxSDK.getChildFile ("Utilities").getChildFile ("CreatePackage.bat");
RelativePath iconFilePath = getAAXIconFile();
auto outputFilename = config.getOutputFilename (".aaxplugin", true);
auto outputFilename = config.getOutputFilename (".aaxplugin", true, false);
auto bundleDir = getOwner().getOutDirFile (config, outputFilename);
auto bundleContents = bundleDir + "\\Contents";
auto archDir = bundleContents + String ("\\") + (config.is64Bit() ? "x64" : "Win32");
auto executable = archDir + String ("\\") + outputFilename;
auto pkgScript = String ("copy /Y ") + getOutputFilePath (config).quoted() + String (" ") + executable.quoted() + String ("\r\ncall ")
auto pkgScript = String ("copy /Y ") + getOutputFilePath (config, false).quoted() + String (" ") + executable.quoted() + String ("\r\ncall ")
+ createRebasedPath (bundleScript) + String (" ") + archDir.quoted() + String (" ") + createRebasedPath (iconFilePath);
if (config.isPluginBinaryCopyStepEnabled())
@@ -1093,6 +1100,24 @@ public:
return pkgScript;
}
else if (type == UnityPlugIn)
{
RelativePath scriptPath (config.project.getGeneratedCodeFolder().getChildFile (config.project.getUnityScriptName()),
getOwner().getTargetFolder(),
RelativePath::projectFolder);
auto pkgScript = String ("copy /Y ") + scriptPath.toWindowsStyle().quoted() + " \"$(OutDir)\"";
if (config.isPluginBinaryCopyStepEnabled())
{
auto copyLocation = config.getUnityPluginBinaryLocationString();
pkgScript += "\r\ncopy /Y \"$(OutDir)$(TargetFileName)\" " + String (copyLocation + "\\$(TargetFileName)").quoted();
pkgScript += "\r\ncopy /Y " + String ("$(OutDir)" + config.project.getUnityScriptName()).quoted() + " " + String (copyLocation + "\\" + config.project.getUnityScriptName()).quoted();
}
return pkgScript;
}
else if (config.isPluginBinaryCopyStepEnabled())
{
auto copyScript = String ("copy /Y \"$(OutDir)$(TargetFileName)\"") + String (" \"$COPYDIR$\\$(TargetFileName)\"");
@@ -1111,7 +1136,7 @@ public:
{
String script;
auto bundleDir = getOwner().getOutDirFile (config, config.getOutputFilename (".aaxplugin", false));
auto bundleDir = getOwner().getOutDirFile (config, config.getOutputFilename (".aaxplugin", false, false));
auto bundleContents = bundleDir + "\\Contents";
auto archDir = bundleContents + String ("\\") + (config.is64Bit() ? "x64" : "Win32");
@@ -1210,14 +1235,14 @@ public:
return searchPaths;
}
String getBinaryNameWithSuffix (const MSVCBuildConfiguration& config) const
String getBinaryNameWithSuffix (const MSVCBuildConfiguration& config, bool forceUnityPrefix) const
{
return config.getOutputFilename (getTargetSuffix(), true);
return config.getOutputFilename (getTargetSuffix(), true, forceUnityPrefix);
}
String getOutputFilePath (const MSVCBuildConfiguration& config) const
String getOutputFilePath (const MSVCBuildConfiguration& config, bool forceUnityPrefix) const
{
return getOwner().getOutDirFile (config, getBinaryNameWithSuffix (config));
return getOwner().getOutDirFile (config, getBinaryNameWithSuffix (config, forceUnityPrefix));
}
StringArray getLibrarySearchPaths (const BuildConfiguration& config) const
@@ -1244,7 +1269,7 @@ public:
if (type != SharedCodeTarget)
if (auto* shared = getOwner().getSharedCodeTarget())
libraries.add (shared->getBinaryNameWithSuffix (config));
libraries.add (shared->getBinaryNameWithSuffix (config, false));
return libraries.joinIntoString (";");
}
@@ -1325,6 +1350,7 @@ public:
case ProjectType::Target::VST3PlugIn:
case ProjectType::Target::AAXPlugIn:
case ProjectType::Target::RTASPlugIn:
case ProjectType::Target::UnityPlugIn:
case ProjectType::Target::DynamicLibrary:
return true;
default:
@@ -1344,8 +1370,6 @@ public:
}
//==============================================================================
const String& getProjectName() const { return projectName; }
bool launchProject() override
{
#if JUCE_WINDOWS


+ 2
- 0
extras/Projucer/Source/ProjectSaving/jucer_ProjectExport_Make.h View File

@@ -179,6 +179,7 @@ public:
switch (type)
{
case VSTPlugIn:
case UnityPlugIn:
case DynamicLibrary: return ".so";
case SharedCodeTarget:
case StaticLibrary: return ".a";
@@ -362,6 +363,7 @@ public:
case ProjectType::Target::VSTPlugIn:
case ProjectType::Target::StandalonePlugIn:
case ProjectType::Target::DynamicLibrary:
case ProjectType::Target::UnityPlugIn:
return true;
default:
break;


+ 47
- 3
extras/Projucer/Source/ProjectSaving/jucer_ProjectExport_Xcode.h View File

@@ -179,6 +179,7 @@ public:
case ProjectType::Target::RTASPlugIn:
case ProjectType::Target::AudioUnitPlugIn:
case ProjectType::Target::DynamicLibrary:
case ProjectType::Target::UnityPlugIn:
return ! iOS;
default:
break;
@@ -442,7 +443,8 @@ protected:
vst3BinaryLocation (config, Ids::vst3BinaryLocation, getUndoManager(), "$(HOME)/Library/Audio/Plug-Ins/VST3/"),
auBinaryLocation (config, Ids::auBinaryLocation, getUndoManager(), "$(HOME)/Library/Audio/Plug-Ins/Components/"),
rtasBinaryLocation (config, Ids::rtasBinaryLocation, getUndoManager(), "/Library/Application Support/Digidesign/Plug-Ins/"),
aaxBinaryLocation (config, Ids::aaxBinaryLocation, getUndoManager(), "/Library/Application Support/Avid/Audio/Plug-Ins/")
aaxBinaryLocation (config, Ids::aaxBinaryLocation, getUndoManager(), "/Library/Application Support/Avid/Audio/Plug-Ins/"),
unityPluginBinaryLocation (config, Ids::unityPluginBinaryLocation, getUndoManager())
{
updateOldPluginBinaryLocations();
updateOldSDKDefaults();
@@ -539,6 +541,7 @@ protected:
String getAUBinaryLocationString() const { return auBinaryLocation.get(); }
String getRTASBinaryLocationString() const { return rtasBinaryLocation.get();}
String getAAXBinaryLocationString() const { return aaxBinaryLocation.get();}
String getUnityPluginBinaryLocationString() const { return unityPluginBinaryLocation.get(); }
private:
//==========================================================================
@@ -547,7 +550,8 @@ protected:
ValueWithDefault osxSDKVersion, osxDeploymentTarget, iosDeploymentTarget, osxArchitecture,
customXcodeFlags, plistPreprocessorDefinitions, codeSignIdentity,
fastMathEnabled, stripLocalSymbolsEnabled, pluginBinaryCopyStepEnabled,
vstBinaryLocation, vst3BinaryLocation, auBinaryLocation, rtasBinaryLocation, aaxBinaryLocation;
vstBinaryLocation, vst3BinaryLocation, auBinaryLocation, rtasBinaryLocation,
aaxBinaryLocation, unityPluginBinaryLocation;
//==========================================================================
void addXcodePluginInstallPathProperties (PropertyListBuilder& props)
@@ -583,6 +587,11 @@ protected:
props.add (new TextPropertyComponentWithEnablement (aaxBinaryLocation, pluginBinaryCopyStepEnabled, "AAX Binary Location",
1024, false),
"The folder in which the compiled AAX binary should be placed.");
if (project.shouldBuildUnityPlugin())
props.add (new TextPropertyComponentWithEnablement (unityPluginBinaryLocation, pluginBinaryCopyStepEnabled, "Unity Binary Location",
1024, false),
"The folder in which the compiled Unity plugin binary and associated C# GUI script should be placed.");
}
void updateOldPluginBinaryLocations()
@@ -734,6 +743,15 @@ public:
xcodeCopyToProductInstallPathAfterBuild = true;
break;
case UnityPlugIn:
xcodePackageType = "BNDL";
xcodeBundleSignature = "????";
xcodeFileType = "wrapper.cfbundle";
xcodeBundleExtension = ".bundle";
xcodeProductType = "com.apple.product-type.bundle";
xcodeCopyToProductInstallPathAfterBuild = true;
break;
case SharedCodeTarget:
xcodeFileType = "archive.ar";
xcodeBundleExtension = ".a";
@@ -822,7 +840,7 @@ public:
if (ProjectExporter::BuildConfiguration::Ptr config = owner.getConfiguration(0))
{
auto productName = owner.replacePreprocessorTokens (*config, config->getTargetBinaryNameString());
auto productName = owner.replacePreprocessorTokens (*config, config->getTargetBinaryNameString (type == UnityPlugIn));
if (xcodeFileType == "archive.ar")
productName = getStaticLibbedFilename (productName);
@@ -995,6 +1013,7 @@ public:
return s;
}
s.set ("PRODUCT_NAME", owner.replacePreprocessorTokens (config, config.getTargetBinaryNameString (type == UnityPlugIn)).quoted());
s.set ("PRODUCT_BUNDLE_IDENTIFIER", getBundleIdentifier());
auto arch = (! owner.isiOS() && type == Target::AudioUnitv3PlugIn) ? osxArch_64Bit
@@ -1231,6 +1250,7 @@ public:
case AudioUnitPlugIn: return config.isPluginBinaryCopyStepEnabled() ? config.getAUBinaryLocationString() : String();
case RTASPlugIn: return config.isPluginBinaryCopyStepEnabled() ? config.getRTASBinaryLocationString() : String();
case AAXPlugIn: return config.isPluginBinaryCopyStepEnabled() ? config.getAAXBinaryLocationString() : String();
case UnityPlugIn: return config.isPluginBinaryCopyStepEnabled() ? config.getUnityPluginBinaryLocationString() : String();
case SharedCodeTarget: return owner.isiOS() ? "@executable_path/Frameworks" : "@executable_path/../Frameworks";
default: return {};
}
@@ -1927,6 +1947,10 @@ private:
&& project.shouldBuildStandalonePlugin() && target->type == XcodeTarget::StandalonePlugIn)
embedAppExtension();
if (project.getProjectType().isAudioPlugin() && project.shouldBuildUnityPlugin()
&& target->type == XcodeTarget::UnityPlugIn)
embedUnityScript();
addTargetObject (*target);
}
}
@@ -1944,6 +1968,25 @@ private:
}
}
void embedUnityScript() const
{
if (auto* unityTarget = getTargetOfType (XcodeTarget::UnityPlugIn))
{
RelativePath scriptPath (getProject().getGeneratedCodeFolder().getChildFile (getProject().getUnityScriptName()),
getTargetFolder(),
RelativePath::buildTargetFolder);
auto path = scriptPath.toUnixStyle();
auto refID = addFileReference (path);
auto fileID = addBuildFile (path, refID, false, false);
resourceIDs.add (fileID);
resourceFileRefs.add (refID);
unityTarget->addCopyFilesPhase ("Embed Unity Script", fileID, kWrapperFolder);
}
}
static Image fixMacIconImageSize (Drawable& image)
{
const int validSizes[] = { 16, 32, 48, 128, 256, 512, 1024 };
@@ -1992,6 +2035,7 @@ private:
v->setProperty ("dependencies", indentParenthesisedList (getTargetDependencies (target)), nullptr);
v->setProperty (Ids::name, target.getXcodeSchemeName(), nullptr);
v->setProperty ("productName", projectName, nullptr);
if (target.type != XcodeTarget::AggregateTarget)


+ 2
- 1
extras/Projucer/Source/ProjectSaving/jucer_ProjectExporter.cpp View File

@@ -450,7 +450,8 @@ void ProjectExporter::addTargetSpecificPreprocessorDefs (StringPairArray& defs,
{"JucePlugin_Build_AUv3", ProjectType::Target::AudioUnitv3PlugIn},
{"JucePlugin_Build_RTAS", ProjectType::Target::RTASPlugIn},
{"JucePlugin_Build_AAX", ProjectType::Target::AAXPlugIn},
{"JucePlugin_Build_Standalone", ProjectType::Target::StandalonePlugIn}
{"JucePlugin_Build_Standalone", ProjectType::Target::StandalonePlugIn},
{"JucePlugin_Build_Unity", ProjectType::Target::UnityPlugIn}
};
if (targetType == ProjectType::Target::SharedCodeTarget)


+ 5
- 1
extras/Projucer/Source/ProjectSaving/jucer_ProjectExporter.h View File

@@ -244,8 +244,12 @@ public:
String getName() const { return configNameValue.get(); }
bool isDebug() const { return isDebugValue.get(); }
String getTargetBinaryNameString() const { return targetNameValue.get(); }
String getTargetBinaryRelativePathString() const { return targetBinaryPathValue.get(); }
String getTargetBinaryNameString (bool isUnityPlugin = false) const
{
return (isUnityPlugin ? Project::addUnityPluginPrefixIfNecessary (targetNameValue.get().toString())
: targetNameValue.get().toString());
}
int getOptimisationLevelInt() const { return optimisationLevelValue.get(); }
String getGCCOptimisationFlag() const;


+ 1
- 0
extras/Projucer/Source/ProjectSaving/jucer_ProjectSaver.cpp View File

@@ -83,6 +83,7 @@ void ProjectSaver::writePluginCharacteristicsFile()
flags.set ("JucePlugin_Build_RTAS", boolToString (project.shouldBuildRTAS()));
flags.set ("JucePlugin_Build_AAX", boolToString (project.shouldBuildAAX()));
flags.set ("JucePlugin_Build_Standalone", boolToString (project.shouldBuildStandalonePlugin()));
flags.set ("JucePlugin_Build_Unity", boolToString (project.shouldBuildUnityPlugin()));
flags.set ("JucePlugin_Enable_IAA", boolToString (project.shouldEnableIAA()));
flags.set ("JucePlugin_Name", toStringLiteral (project.getPluginNameString()));
flags.set ("JucePlugin_Desc", toStringLiteral (project.getPluginDescriptionString()));


+ 23
- 0
extras/Projucer/Source/ProjectSaving/jucer_ProjectSaver.h View File

@@ -94,8 +94,13 @@ public:
auto projectRootHash = project.getProjectRoot().toXmlString().hashCode();
if (project.getProjectType().isAudioPlugin())
{
writePluginCharacteristicsFile();
if (project.shouldBuildUnityPlugin())
writeUnityScriptFile();
}
writeAppConfigFile (modules, appConfigUserContent);
writeBinaryDataFiles();
writeAppHeader (modules);
@@ -669,6 +674,24 @@ private:
void writePluginCharacteristicsFile();
void writeUnityScriptFile()
{
String unityScriptContents (BinaryData::jucer_UnityPluginGUIScript_cs);
auto projectName = Project::addUnityPluginPrefixIfNecessary (project.getProjectNameString());
unityScriptContents = unityScriptContents.replace ("%%plugin_name%%", projectName)
.replace ("%%plugin_vendor%%", project.getPluginManufacturerString())
.replace ("%%plugin_description%%", project.getPluginDescriptionString());
auto f = getGeneratedCodeFolder().getChildFile (project.getUnityScriptName());
MemoryOutputStream out;
out << unityScriptContents;
replaceFileIfDifferent (f, out);
}
void writeProjects (const OwnedArray<LibraryModule>&, const String&, bool);
void saveExporter (ProjectExporter* exporter, const OwnedArray<LibraryModule>& modules)


+ 2
- 0
extras/Projucer/Source/Utility/Helpers/jucer_PresetIDs.h View File

@@ -118,6 +118,7 @@ namespace Ids
DECLARE_ID (auBinaryLocation);
DECLARE_ID (rtasBinaryLocation);
DECLARE_ID (aaxBinaryLocation);
DECLARE_ID (unityPluginBinaryLocation);
DECLARE_ID (enablePluginBinaryCopyStep);
DECLARE_ID (stripLocalSymbols);
DECLARE_ID (osxSDK);
@@ -298,6 +299,7 @@ namespace Ids
DECLARE_ID (buildRTAS);
DECLARE_ID (buildAAX);
DECLARE_ID (buildStandalone);
DECLARE_ID (buildUnity);
DECLARE_ID (enableIAA);
DECLARE_ID (pluginName);
DECLARE_ID (pluginDesc);


+ 191
- 0
modules/juce_audio_plugin_client/Unity/juce_UnityPluginInterface.h View File

@@ -0,0 +1,191 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2017 - ROLI Ltd.
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 5 End-User License
Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
27th April 2017).
End User License Agreement: www.juce.com/juce-5-licence
Privacy Policy: www.juce.com/juce-5-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
#pragma once
//==============================================================================
#define UNITY_AUDIO_PLUGIN_API_VERSION 0x010401
#if JUCE_WINDOWS
#define UNITY_INTERFACE_API __stdcall
#define UNITY_INTERFACE_EXPORT __declspec(dllexport)
#else
#define UNITY_INTERFACE_API
#define UNITY_INTERFACE_EXPORT __attribute__ ((visibility("default")))
#endif
//==============================================================================
struct UnityAudioEffectState;
typedef int (UNITY_INTERFACE_API * createCallback) (UnityAudioEffectState* state);
typedef int (UNITY_INTERFACE_API * releaseCallback) (UnityAudioEffectState* state);
typedef int (UNITY_INTERFACE_API * resetCallback) (UnityAudioEffectState* state);
typedef int (UNITY_INTERFACE_API * processCallback) (UnityAudioEffectState* state, float* inBuffer, float* outBuffer, unsigned int bufferSize,
int numInChannels, int numOutChannels);
typedef int (UNITY_INTERFACE_API * setPositionCallback) (UnityAudioEffectState* state, unsigned int pos);
typedef int (UNITY_INTERFACE_API * setFloatParameterCallback) (UnityAudioEffectState* state, int index, float value);
typedef int (UNITY_INTERFACE_API * getFloatParameterCallback) (UnityAudioEffectState* state, int index, float* value, char* valuestr);
typedef int (UNITY_INTERFACE_API * getFloatBufferCallback) (UnityAudioEffectState* state, const char* name, float* buffer, int numsamples);
typedef int (UNITY_INTERFACE_API * distanceAttenuationCallback) (UnityAudioEffectState* state, float distanceIn, float attenuationIn, float* attenuationOut);
typedef void (UNITY_INTERFACE_API * renderCallback) (int eventId);
//==============================================================================
enum UnityAudioEffectDefinitionFlags
{
isSideChainTarget = 1,
isSpatializer = 2,
isAmbisonicDecoder = 4,
appliesDistanceAttenuation = 8
};
enum UnityAudioEffectStateFlags
{
stateIsPlaying = 1,
stateIsPaused = 2,
stateIsMuted = 8,
statIsSideChainTarget = 16
};
enum UnityEventModifiers
{
shift = 1,
control = 2,
alt = 4,
command = 8,
numeric = 16,
capsLock = 32,
functionKey = 64
};
//==============================================================================
struct UnityAudioSpatializerData
{
float listenerMatrix[16];
float sourceMatrix[16];
float spatialBlend;
float reverbZoneMix;
float spread;
float stereoPan;
distanceAttenuationCallback distanceAttenuationCallback;
float minDistance;
float maxDistance;
};
struct UnityAudioAmbisonicData
{
float listenerMatrix[16];
float sourceMatrix[16];
float spatialBlend;
float reverbZoneMix;
float spread;
float stereoPan;
distanceAttenuationCallback distanceAttenuationCallback;
int ambisonicOutChannels;
float volume;
};
struct UnityAudioEffectState
{
juce::uint32 structSize;
juce::uint32 sampleRate;
juce::uint64 dspCurrentTick;
juce::uint64 dspPreviousTick;
float* sidechainBuffer;
void* effectData;
juce::uint32 flags;
void* internal;
UnityAudioSpatializerData* spatializerData;
juce::uint32 dspBufferSize;
juce::uint32 hostAPIVersion;
UnityAudioAmbisonicData* ambisonicData;
template<typename T>
inline T* getEffectData() const
{
jassert (effectData != nullptr);
jassert (internal != nullptr);
return (T*) effectData;
}
};
struct UnityAudioParameterDefinition
{
char name[16];
char unit[16];
const char* description;
float min;
float max;
float defaultVal;
float displayScale;
float displayExponent;
};
struct UnityAudioEffectDefinition
{
juce::uint32 structSize;
juce::uint32 parameterStructSize;
juce::uint32 apiVersion;
juce::uint32 pluginVersion;
juce::uint32 channels;
juce::uint32 numParameters;
juce::uint64 flags;
char name[32];
createCallback create;
releaseCallback release;
resetCallback reset;
processCallback process;
setPositionCallback setPosition;
UnityAudioParameterDefinition* parameterDefintions;
setFloatParameterCallback setFloatParameter;
getFloatParameterCallback getFloatParameter;
getFloatBufferCallback getFloatBuffer;
};
//==============================================================================
// Unity callback
extern "C" UNITY_INTERFACE_EXPORT int UNITY_INTERFACE_API UnityGetAudioEffectDefinitions (UnityAudioEffectDefinition*** definitionsPtr);
// GUI script callbacks
extern "C" UNITY_INTERFACE_EXPORT renderCallback UNITY_INTERFACE_API getRenderCallback();
extern "C" UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API unityInitialiseTexture (int id, void* textureHandle, int w, int h);
extern "C" UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API unityMouseDown (int id, float x, float y, UnityEventModifiers mods, int button);
extern "C" UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API unityMouseDrag (int id, float x, float y, UnityEventModifiers mods, int button);
extern "C" UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API unityMouseUp (int id, float x, float y, UnityEventModifiers mods);
extern "C" UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API unityKeyEvent (int id, int code, UnityEventModifiers mods, const char* name);
extern "C" UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API unitySetScreenBounds (int id, float x, float y, float w, float h);

+ 779
- 0
modules/juce_audio_plugin_client/Unity/juce_Unity_Wrapper.cpp View File

@@ -0,0 +1,779 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2017 - ROLI Ltd.
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 5 End-User License
Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
27th April 2017).
End User License Agreement: www.juce.com/juce-5-licence
Privacy Policy: www.juce.com/juce-5-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
#if JucePlugin_Build_Unity
#include "../../juce_core/system/juce_TargetPlatform.h"
#include "../utility/juce_IncludeModuleHeaders.h"
#include "../../juce_audio_processors/format_types/juce_LegacyAudioParameter.cpp"
#if JUCE_WINDOWS
#include "../utility/juce_IncludeSystemHeaders.h"
#endif
#include "juce_UnityPluginInterface.h"
//==============================================================================
namespace juce
{
typedef ComponentPeer* (*createUnityPeerFunctionType) (Component&);
extern createUnityPeerFunctionType juce_createUnityPeerFn;
//==============================================================================
class UnityPeer : public ComponentPeer,
public AsyncUpdater
{
public:
UnityPeer (Component& ed)
: ComponentPeer (ed, 0),
mouseWatcher (*this)
{
getEditor().setResizable (false, false);
}
//==============================================================================
Rectangle<int> getBounds() const override { return bounds; }
Point<float> localToGlobal (Point<float> relativePosition) override { return relativePosition + getBounds().getPosition().toFloat(); }
Point<float> globalToLocal (Point<float> screenPosition) override { return screenPosition - getBounds().getPosition().toFloat(); }
StringArray getAvailableRenderingEngines() override { return StringArray ("Software Renderer"); }
void setBounds (const Rectangle<int>& newBounds, bool) override
{
bounds = newBounds;
mouseWatcher.setBoundsToWatch (bounds);
}
bool contains (Point<int> localPos, bool) const override
{
if (isPositiveAndBelow (localPos.getX(), getBounds().getWidth())
&& isPositiveAndBelow (localPos.getY(), getBounds().getHeight()))
return true;
return false;
}
void handleAsyncUpdate() override
{
fillPixels();
}
//==============================================================================
AudioProcessorEditor& getEditor() { return *dynamic_cast<AudioProcessorEditor*> (&getComponent()); }
void setPixelDataHandle (uint8* handle, int width, int height)
{
pixelData = handle;
textureWidth = width;
textureHeight = height;
renderImage = Image (new UnityBitmapImage (pixelData, width, height));
}
// N.B. This is NOT an efficient way to do this and you shouldn't use this method in your own code.
// It works for our purposes here but a much more efficient way would be to use a GL texture.
void fillPixels()
{
if (pixelData == nullptr)
return;
LowLevelGraphicsSoftwareRenderer renderer (renderImage);
renderer.addTransform (AffineTransform::verticalFlip ((float) getComponent().getHeight()));
handlePaint (renderer);
for (int i = 0; i < textureWidth * textureHeight * 4; i += 4)
{
auto r = pixelData[i + 2];
auto g = pixelData[i + 1];
auto b = pixelData[i + 0];
pixelData[i + 0] = r;
pixelData[i + 1] = g;
pixelData[i + 2] = b;
}
}
void forwardMouseEvent (Point<float> position, ModifierKeys mods)
{
ModifierKeys::currentModifiers = mods;
handleMouseEvent (juce::MouseInputSource::mouse, position, mods, juce::MouseInputSource::invalidPressure,
juce::MouseInputSource::invalidOrientation, juce::Time::currentTimeMillis());
}
void forwardKeyPress (int code, String name, ModifierKeys mods)
{
ModifierKeys::currentModifiers = mods;
handleKeyPress (getKeyPress (code, name));
}
private:
//==============================================================================
struct UnityBitmapImage : public ImagePixelData
{
UnityBitmapImage (uint8* data, int w, int h)
: ImagePixelData (Image::PixelFormat::ARGB, w, h),
imageData (data),
lineStride (width * pixelStride)
{
}
ImageType* createType() const override { return new SoftwareImageType(); }
LowLevelGraphicsContext* createLowLevelContext() override { return new LowLevelGraphicsSoftwareRenderer (Image (this)); }
void initialiseBitmapData (Image::BitmapData& bitmap, int x, int y, Image::BitmapData::ReadWriteMode mode) override
{
ignoreUnused (mode);
bitmap.data = imageData + x * pixelStride + y * lineStride;
bitmap.pixelFormat = pixelFormat;
bitmap.lineStride = lineStride;
bitmap.pixelStride = pixelStride;
}
ImagePixelData::Ptr clone() override
{
auto im = new UnityBitmapImage (imageData, width, height);
for (int i = 0; i < height; ++i)
memcpy (im->imageData + i * lineStride, imageData + i * lineStride, (size_t) lineStride);
return im;
}
uint8* imageData;
int pixelStride = 4, lineStride;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (UnityBitmapImage)
};
//==============================================================================
struct MouseWatcher : public Timer
{
MouseWatcher (ComponentPeer& o) : owner (o) {}
void timerCallback() override
{
auto pos = Desktop::getMousePosition();
if (boundsToWatch.contains (pos) && pos != lastMousePos)
{
auto ms = Desktop::getInstance().getMainMouseSource();
if (! ms.getCurrentModifiers().isLeftButtonDown())
owner.handleMouseEvent (juce::MouseInputSource::mouse, owner.globalToLocal (pos.toFloat()), {},
juce::MouseInputSource::invalidPressure, juce::MouseInputSource::invalidOrientation, juce::Time::currentTimeMillis());
lastMousePos = pos;
}
}
void setBoundsToWatch (Rectangle<int> b)
{
if (boundsToWatch != b)
boundsToWatch = b;
startTimer (250);
}
ComponentPeer& owner;
Rectangle<int> boundsToWatch;
Point<int> lastMousePos;
};
//==============================================================================
KeyPress getKeyPress (int keyCode, String name)
{
if (keyCode >= 32 && keyCode <= 64)
return { keyCode, ModifierKeys::currentModifiers, juce::juce_wchar (keyCode) };
if (keyCode >= 91 && keyCode <= 122)
return { keyCode, ModifierKeys::currentModifiers, name[0] };
if (keyCode >= 256 && keyCode <= 265)
return { juce::KeyPress::numberPad0 + (keyCode - 256), ModifierKeys::currentModifiers, juce::String (keyCode - 256).getCharPointer()[0] };
if (keyCode == 8) return { juce::KeyPress::backspaceKey, ModifierKeys::currentModifiers, {} };
if (keyCode == 127) return { juce::KeyPress::deleteKey, ModifierKeys::currentModifiers, {} };
if (keyCode == 9) return { juce::KeyPress::tabKey, ModifierKeys::currentModifiers, {} };
if (keyCode == 13) return { juce::KeyPress::returnKey, ModifierKeys::currentModifiers, {} };
if (keyCode == 27) return { juce::KeyPress::escapeKey, ModifierKeys::currentModifiers, {} };
if (keyCode == 32) return { juce::KeyPress::spaceKey, ModifierKeys::currentModifiers, {} };
if (keyCode == 266) return { juce::KeyPress::numberPadDecimalPoint, ModifierKeys::currentModifiers, {} };
if (keyCode == 267) return { juce::KeyPress::numberPadDivide, ModifierKeys::currentModifiers, {} };
if (keyCode == 268) return { juce::KeyPress::numberPadMultiply, ModifierKeys::currentModifiers, {} };
if (keyCode == 269) return { juce::KeyPress::numberPadSubtract, ModifierKeys::currentModifiers, {} };
if (keyCode == 270) return { juce::KeyPress::numberPadAdd, ModifierKeys::currentModifiers, {} };
if (keyCode == 272) return { juce::KeyPress::numberPadEquals, ModifierKeys::currentModifiers, {} };
if (keyCode == 273) return { juce::KeyPress::upKey, ModifierKeys::currentModifiers, {} };
if (keyCode == 274) return { juce::KeyPress::downKey, ModifierKeys::currentModifiers, {} };
if (keyCode == 275) return { juce::KeyPress::rightKey, ModifierKeys::currentModifiers, {} };
if (keyCode == 276) return { juce::KeyPress::leftKey, ModifierKeys::currentModifiers, {} };
return {};
}
//==============================================================================
Rectangle<int> bounds;
MouseWatcher mouseWatcher;
uint8* pixelData = nullptr;
int textureWidth, textureHeight;
Image renderImage;
//==============================================================================
void setMinimised (bool) override {}
bool isMinimised() const override { return false; }
void setFullScreen (bool) override {}
bool isFullScreen() const override { return false; }
bool setAlwaysOnTop (bool) override { return false; }
void toFront (bool) override {}
void toBehind (ComponentPeer*) override {}
bool isFocused() const override { return true; }
void grabFocus() override {}
void* getNativeHandle() const override { return nullptr; }
BorderSize<int> getFrameSize() const override { return {}; }
void setVisible (bool) override {}
void setTitle (const String&) override {}
void setIcon (const Image&) override {}
void textInputRequired (Point<int>, TextInputTarget&) override {}
void setAlpha (float) override {}
void performAnyPendingRepaintsNow() override {}
void repaint (const Rectangle<int>&) override {}
//==============================================================================
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (UnityPeer)
};
ComponentPeer* createUnityPeer (Component& c) { return new UnityPeer (c); }
//==============================================================================
class AudioProcessorUnityWrapper
{
public:
AudioProcessorUnityWrapper (bool isTemporary)
{
pluginInstance.reset (createPluginFilterOfType (AudioProcessor::wrapperType_Unity));
if (! isTemporary && pluginInstance->hasEditor())
{
pluginInstanceEditor.reset (pluginInstance->createEditorIfNeeded());
pluginInstanceEditor->setVisible (true);
pluginInstanceEditor->addToDesktop (0);
}
juceParameters.update (*pluginInstance, false);
}
~AudioProcessorUnityWrapper()
{
if (pluginInstanceEditor != nullptr)
{
pluginInstanceEditor->removeFromDesktop();
PopupMenu::dismissAllActiveMenus();
pluginInstanceEditor->processor.editorBeingDeleted (pluginInstanceEditor.get());
pluginInstanceEditor = nullptr;
}
}
void create (UnityAudioEffectState* state)
{
// only supported in Unity plugin API > 1.0
if (state->structSize >= sizeof (UnityAudioEffectState))
samplesPerBlock = state->dspBufferSize;
pluginInstance->setRateAndBufferSizeDetails (state->sampleRate, samplesPerBlock);
pluginInstance->prepareToPlay (state->sampleRate, samplesPerBlock);
scratchBuffer.setSize (jmax (pluginInstance->getTotalNumInputChannels(), pluginInstance->getTotalNumOutputChannels()), samplesPerBlock);
}
void release()
{
pluginInstance->releaseResources();
}
void reset()
{
pluginInstance->reset();
}
void process (float* inBuffer, float* outBuffer, unsigned int bufferSize, int numInChannels, int numOutChannels, bool isBypassed)
{
for (int pos = 0; pos < static_cast<int> (bufferSize);)
{
auto max = jmin (static_cast<int> (bufferSize) - pos, samplesPerBlock);
processBuffers (inBuffer + (pos * numInChannels), outBuffer + (pos * numOutChannels), max, numInChannels, numOutChannels, isBypassed);
pos += max;
}
}
void declareParameters (UnityAudioEffectDefinition& definition)
{
static std::unique_ptr<UnityAudioParameterDefinition> parametersPtr;
static int numParams = 0;
if (parametersPtr == nullptr)
{
auto paramsCopy = juceParameters.params;
for (auto* parameter : paramsCopy)
{
// Unity only displays parameters using a slider so remove any choice parameters
if (! parameter->getAllValueStrings().isEmpty())
paramsCopy.remove (paramsCopy.indexOf (parameter));
}
numParams = paramsCopy.size();
parametersPtr.reset (static_cast<UnityAudioParameterDefinition*> (std::calloc (static_cast<size_t> (numParams),
sizeof (UnityAudioParameterDefinition))));
parameterDescriptions.clear();
for (int i = 0; i < numParams; ++i)
{
auto* parameter = paramsCopy[i];
auto& paramDef = parametersPtr.get()[i];
strncpy (paramDef.name, parameter->getName (15).toRawUTF8(), 15);
if (parameter->getLabel().isNotEmpty())
strncpy (paramDef.unit, parameter->getLabel().toRawUTF8(), 15);
parameterDescriptions.add (parameter->getName (15));
paramDef.description = parameterDescriptions[i].toRawUTF8();
paramDef.defaultVal = parameter->getDefaultValue();
paramDef.min = 0.0f;
paramDef.max = 1.0f;
float scale = 1.0f;
float exp = 1.0f;
if (auto* floatParam = dynamic_cast<AudioParameterFloat*> (parameter))
{
scale = floatParam->range.end;
exp = floatParam->range.skew;
}
else if (auto* intParam = dynamic_cast<AudioParameterInt*> (parameter))
{
scale = (float) intParam->getRange().getEnd();
}
paramDef.displayScale = scale;
paramDef.displayExponent = exp;
}
}
definition.numParameters = numParams;
definition.parameterDefintions = parametersPtr.get();
}
void setParameter (int index, float value) { juceParameters.getParamForIndex (index)->setValue (value); }
float getParameter (int index) const noexcept { return juceParameters.getParamForIndex (index)->getValue(); }
String getParameterString (int index) const noexcept
{
auto* param = juceParameters.getParamForIndex (index);
return param->getText (param->getValue(), 16);
}
int getNumInputChannels() const noexcept { return pluginInstance->getTotalNumInputChannels(); }
int getNumOutputChannels() const noexcept { return pluginInstance->getTotalNumOutputChannels(); }
bool hasEditor() const noexcept { return pluginInstance->hasEditor(); }
UnityPeer& getEditorPeer() const
{
auto* peer = dynamic_cast<UnityPeer*> (pluginInstanceEditor->getPeer());
jassert (peer != nullptr);
return *peer;
}
private:
//==============================================================================
void processBuffers (float* inBuffer, float* outBuffer, unsigned int bufferSize, int numInChannels, int numOutChannels, bool isBypassed)
{
int ch;
for (ch = 0; ch < numInChannels; ++ch)
{
using DstSampleType = AudioData::Pointer<AudioData::Float32, AudioData::NativeEndian, AudioData::NonInterleaved, AudioData::NonConst>;
using SrcSampleType = AudioData::Pointer<AudioData::Float32, AudioData::NativeEndian, AudioData::Interleaved, AudioData::Const>;
DstSampleType dstData (scratchBuffer.getWritePointer (ch));
SrcSampleType srcData (inBuffer + ch, numInChannels);
dstData.convertSamples (srcData, bufferSize);
}
for (; ch < numOutChannels; ++ch)
scratchBuffer.clear (ch, 0, bufferSize);
{
const ScopedLock sl (pluginInstance->getCallbackLock());
if (pluginInstance->isSuspended())
{
scratchBuffer.clear();
}
else
{
MidiBuffer mb;
if (isBypassed)
pluginInstance->processBlockBypassed (scratchBuffer, mb);
else
pluginInstance->processBlock (scratchBuffer, mb);
}
}
for (ch = 0; ch < numOutChannels; ++ch)
{
using DstSampleType = AudioData::Pointer<AudioData::Float32, AudioData::NativeEndian, AudioData::Interleaved, AudioData::NonConst>;
using SrcSampleType = AudioData::Pointer<AudioData::Float32, AudioData::NativeEndian, AudioData::NonInterleaved, AudioData::Const>;
DstSampleType dstData (outBuffer + ch, numOutChannels);
SrcSampleType srcData (scratchBuffer.getReadPointer (ch));
dstData.convertSamples (srcData, bufferSize);
}
}
//==============================================================================
std::unique_ptr<AudioProcessor> pluginInstance;
std::unique_ptr<AudioProcessorEditor> pluginInstanceEditor;
int samplesPerBlock = 1024;
StringArray parameterDescriptions;
AudioBuffer<float> scratchBuffer;
LegacyAudioParametersWrapper juceParameters;
//==============================================================================
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioProcessorUnityWrapper)
};
//==============================================================================
HashMap<int, AudioProcessorUnityWrapper*>& getWrapperMap()
{
static HashMap<int, AudioProcessorUnityWrapper*> wrapperMap;
return wrapperMap;
}
static void onWrapperCreation (AudioProcessorUnityWrapper* wrapperToAdd)
{
getWrapperMap().set (std::abs (Random::getSystemRandom().nextInt (65536)), wrapperToAdd);
}
static void onWrapperDeletion (AudioProcessorUnityWrapper* wrapperToRemove)
{
getWrapperMap().removeValue (wrapperToRemove);
}
//==============================================================================
namespace UnityCallbacks
{
int UNITY_INTERFACE_API createCallback (UnityAudioEffectState* state)
{
if (getWrapperMap().size() == 0)
initialiseJuce_GUI();
auto* pluginInstance = new AudioProcessorUnityWrapper (false);
pluginInstance->create (state);
state->effectData = pluginInstance;
onWrapperCreation (pluginInstance);
return 0;
}
int UNITY_INTERFACE_API releaseCallback (UnityAudioEffectState* state)
{
auto* pluginInstance = state->getEffectData<AudioProcessorUnityWrapper>();
pluginInstance->release();
onWrapperDeletion (pluginInstance);
delete pluginInstance;
if (getWrapperMap().size() == 0)
shutdownJuce_GUI();
return 0;
}
int UNITY_INTERFACE_API resetCallback (UnityAudioEffectState* state)
{
auto* pluginInstance = state->getEffectData<AudioProcessorUnityWrapper>();
pluginInstance->reset();
return 0;
}
int UNITY_INTERFACE_API setPositionCallback (UnityAudioEffectState* state, unsigned int pos)
{
ignoreUnused (state, pos);
return 0;
}
int UNITY_INTERFACE_API setFloatParameterCallback (UnityAudioEffectState* state, int index, float value)
{
auto* pluginInstance = state->getEffectData<AudioProcessorUnityWrapper>();
pluginInstance->setParameter (index, value);
return 0;
}
int UNITY_INTERFACE_API getFloatParameterCallback (UnityAudioEffectState* state, int index, float* value, char* valueStr)
{
auto* pluginInstance = state->getEffectData<AudioProcessorUnityWrapper>();
*value = pluginInstance->getParameter (index);
strncpy (valueStr, pluginInstance->getParameterString (index).toRawUTF8(), 15);
return 0;
}
int UNITY_INTERFACE_API getFloatBufferCallback (UnityAudioEffectState* state, const char* name, float* buffer, int numSamples)
{
ignoreUnused (numSamples);
auto nameStr = String (name);
if (nameStr == "Editor")
{
auto* pluginInstance = state->getEffectData<AudioProcessorUnityWrapper>();
buffer[0] = pluginInstance->hasEditor() ? 1.0f : 0.0f;
}
else if (nameStr == "ID")
{
auto* pluginInstance = state->getEffectData<AudioProcessorUnityWrapper>();
for (HashMap<int, AudioProcessorUnityWrapper*>::Iterator i (getWrapperMap()); i.next();)
{
if (i.getValue() == pluginInstance)
{
buffer[0] = (float) i.getKey();
break;
}
}
return 0;
}
else if (nameStr == "Size")
{
auto* pluginInstance = state->getEffectData<AudioProcessorUnityWrapper>();
auto& editor = pluginInstance->getEditorPeer().getEditor();
buffer[0] = (float) editor.getBounds().getWidth();
buffer[1] = (float) editor.getBounds().getHeight();
buffer[2] = (float) editor.getConstrainer()->getMinimumWidth();
buffer[3] = (float) editor.getConstrainer()->getMinimumHeight();
buffer[4] = (float) editor.getConstrainer()->getMaximumWidth();
buffer[5] = (float) editor.getConstrainer()->getMaximumHeight();
}
return 0;
}
int UNITY_INTERFACE_API processCallback (UnityAudioEffectState* state, float* inBuffer, float* outBuffer,
unsigned int bufferSize, int numInChannels, int numOutChannels)
{
auto* pluginInstance = state->getEffectData<AudioProcessorUnityWrapper>();
if (pluginInstance != nullptr)
{
auto isPlaying = ((state->flags & stateIsPlaying) != 0);
auto isMuted = ((state->flags & stateIsMuted) != 0);
auto isPaused = ((state->flags & stateIsPaused) != 0);
auto bypassed = ! isPlaying || (isMuted || isPaused);
pluginInstance->process (inBuffer, outBuffer, bufferSize, numInChannels, numOutChannels, bypassed);
}
else
{
FloatVectorOperations::clear (outBuffer, bufferSize * numOutChannels);
}
return 0;
}
}
//==============================================================================
static void declareEffect (UnityAudioEffectDefinition& definition)
{
memset (&definition, 0, sizeof (definition));
std::unique_ptr<AudioProcessorUnityWrapper> wrapper = std::make_unique<AudioProcessorUnityWrapper> (true);
String name (JucePlugin_Name);
if (! name.startsWithIgnoreCase ("audioplugin"))
name = "audioplugin_" + name;
strcpy (definition.name, name.toRawUTF8());
definition.structSize = sizeof (UnityAudioEffectDefinition);
definition.parameterStructSize = sizeof (UnityAudioParameterDefinition);
definition.apiVersion = UNITY_AUDIO_PLUGIN_API_VERSION;
definition.pluginVersion = JucePlugin_VersionCode;
// effects must set this to 0, generators > 0
definition.channels = (wrapper->getNumInputChannels() != 0 ? 0 : wrapper->getNumOutputChannels());
wrapper->declareParameters (definition);
definition.create = UnityCallbacks::createCallback;
definition.release = UnityCallbacks::releaseCallback;
definition.reset = UnityCallbacks::resetCallback;
definition.setPosition = UnityCallbacks::setPositionCallback;
definition.process = UnityCallbacks::processCallback;
definition.setFloatParameter = UnityCallbacks::setFloatParameterCallback;
definition.getFloatParameter = UnityCallbacks::getFloatParameterCallback;
definition.getFloatBuffer = UnityCallbacks::getFloatBufferCallback;
}
} // namespace juce
UNITY_INTERFACE_EXPORT int UnityGetAudioEffectDefinitions (UnityAudioEffectDefinition*** definitionsPtr)
{
static bool hasSetWrapperType = false;
if (! hasSetWrapperType)
{
juce::PluginHostType::jucePlugInClientCurrentWrapperType = juce::AudioProcessor::wrapperType_Unity;
juce::juce_createUnityPeerFn = juce::createUnityPeer;
hasSetWrapperType = true;
}
auto* definition = new UnityAudioEffectDefinition();
juce::declareEffect (*definition);
*definitionsPtr = &definition;
return 1;
}
//==============================================================================
static juce::ModifierKeys unityModifiersToJUCE (UnityEventModifiers mods, bool mouseDown, int mouseButton = -1)
{
int flags = 0;
if (mouseDown)
{
if (mouseButton == 0)
flags |= juce::ModifierKeys::leftButtonModifier;
else if (mouseButton == 1)
flags |= juce::ModifierKeys::rightButtonModifier;
else if (mouseButton == 2)
flags |= juce::ModifierKeys::middleButtonModifier;
}
if (mods == 0)
return flags;
if ((mods & UnityEventModifiers::shift) != 0) flags |= juce::ModifierKeys::shiftModifier;
if ((mods & UnityEventModifiers::control) != 0) flags |= juce::ModifierKeys::ctrlModifier;
if ((mods & UnityEventModifiers::alt) != 0) flags |= juce::ModifierKeys::altModifier;
if ((mods & UnityEventModifiers::command) != 0) flags |= juce::ModifierKeys::commandModifier;
return { flags };
}
//==============================================================================
static juce::AudioProcessorUnityWrapper* getWrapperChecked (int id)
{
auto* wrapper = juce::getWrapperMap()[id];
jassert (wrapper != nullptr);
return wrapper;
}
//==============================================================================
static void UNITY_INTERFACE_API onRenderEvent (int id)
{
getWrapperChecked (id)->getEditorPeer().triggerAsyncUpdate();
}
UNITY_INTERFACE_EXPORT renderCallback UNITY_INTERFACE_API getRenderCallback()
{
return onRenderEvent;
}
UNITY_INTERFACE_EXPORT void unityInitialiseTexture (int id, void* data, int w, int h)
{
getWrapperChecked (id)->getEditorPeer().setPixelDataHandle (reinterpret_cast<juce::uint8*> (data), w, h);
}
UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API unityMouseDown (int id, float x, float y, UnityEventModifiers unityMods, int button)
{
getWrapperChecked (id)->getEditorPeer().forwardMouseEvent ({ x, y }, unityModifiersToJUCE (unityMods, true, button));
}
UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API unityMouseDrag (int id, float x, float y, UnityEventModifiers unityMods, int button)
{
getWrapperChecked (id)->getEditorPeer().forwardMouseEvent ({ x, y }, unityModifiersToJUCE (unityMods, true, button));
}
UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API unityMouseUp (int id, float x, float y, UnityEventModifiers unityMods)
{
getWrapperChecked (id)->getEditorPeer().forwardMouseEvent ({ x, y }, unityModifiersToJUCE (unityMods, false));
}
UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API unityKeyEvent (int id, int code, UnityEventModifiers mods, const char* name)
{
getWrapperChecked (id)->getEditorPeer().forwardKeyPress (code, name, unityModifiersToJUCE (mods, false));
}
UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API unitySetScreenBounds (int id, float x, float y, float w, float h)
{
getWrapperChecked (id)->getEditorPeer().getEditor().setBounds ({ (int) x, (int) y, (int) w, (int) h });
}
//==============================================================================
#if JUCE_WINDOWS
extern "C" BOOL WINAPI DllMain (HINSTANCE instance, DWORD reason, LPVOID)
{
if (reason == DLL_PROCESS_ATTACH)
juce::Process::setCurrentModuleInstanceHandle (instance);
return true;
}
#endif
#endif

+ 27
- 0
modules/juce_audio_plugin_client/juce_audio_plugin_client_Unity.cpp View File

@@ -0,0 +1,27 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2017 - ROLI Ltd.
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 5 End-User License
Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
27th April 2017).
End User License Agreement: www.juce.com/juce-5-licence
Privacy Policy: www.juce.com/juce-5-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
#include "Unity/juce_Unity_Wrapper.cpp"

+ 2
- 1
modules/juce_audio_plugin_client/utility/juce_CheckSettingMacros.h View File

@@ -30,7 +30,8 @@
#if ! (JucePlugin_Build_VST || JucePlugin_Build_VST3 \
|| JucePlugin_Build_AU || JucePlugin_Build_AUv3 \
||JucePlugin_Build_RTAS || JucePlugin_Build_AAX \
|| JucePlugin_Build_Standalone || JucePlugin_Build_LV2)
|| JucePlugin_Build_Standalone || JucePlugin_Build_LV2 \
|| JucePlugin_Build_Unity)
#error "You need to enable at least one plugin format!"
#endif


+ 4
- 0
modules/juce_audio_plugin_client/utility/juce_PluginUtilities.cpp View File

@@ -39,6 +39,10 @@ namespace juce
AudioProcessor::WrapperType PluginHostType::jucePlugInClientCurrentWrapperType = AudioProcessor::wrapperType_Undefined;
#if JucePlugin_Build_Unity
bool juce_isRunningInUnity() { return PluginHostType::getPluginLoadedAs() == AudioProcessor::wrapperType_Unity; }
#endif
#ifndef JUCE_VST3_CAN_REPLACE_VST2
#define JUCE_VST3_CAN_REPLACE_VST2 1
#endif


+ 2
- 1
modules/juce_audio_processors/processors/juce_AudioProcessor.h View File

@@ -1352,7 +1352,8 @@ public:
wrapperType_AudioUnitv3,
wrapperType_RTAS,
wrapperType_AAX,
wrapperType_Standalone
wrapperType_Standalone,
wrapperType_Unity
};
/** When loaded by a plugin wrapper, this flag will be set to indicate the type


+ 19
- 0
modules/juce_audio_processors/processors/juce_AudioProcessorEditor.cpp View File

@@ -207,4 +207,23 @@ void AudioProcessorEditor::setScaleFactor (float newScale)
editorResized (true);
}
//==============================================================================
#if JUCE_MODULE_AVAILABLE_juce_audio_plugin_client && JucePlugin_Build_Unity
typedef ComponentPeer* (*createUnityPeerFunctionType) (Component&);
createUnityPeerFunctionType juce_createUnityPeerFn = nullptr;
#endif
ComponentPeer* AudioProcessorEditor::createNewPeer (int styleFlags, void* nativeWindow)
{
#if JUCE_MODULE_AVAILABLE_juce_audio_plugin_client && JucePlugin_Build_Unity
if (juce_createUnityPeerFn != nullptr)
{
ignoreUnused (styleFlags, nativeWindow);
return juce_createUnityPeerFn (*this);
}
#endif
return Component::createNewPeer (styleFlags, nativeWindow);
}
} // namespace juce

+ 2
- 0
modules/juce_audio_processors/processors/juce_AudioProcessorEditor.h View File

@@ -193,6 +193,8 @@ private:
JUCE_DECLARE_NON_COPYABLE (AudioProcessorEditorListener)
};
ComponentPeer* createNewPeer (int styleFlags, void*) override;
//==============================================================================
void initialise();
void editorResized (bool wasResized);


+ 10
- 0
modules/juce_events/native/juce_win32_Messaging.cpp View File

@@ -31,6 +31,10 @@ CheckEventBlockedByModalComps isEventBlockedByModalComps = nullptr;
typedef void (*SettingChangeCallbackFunc) (void);
SettingChangeCallbackFunc settingChangeCallback = nullptr;
#if JUCE_MODULE_AVAILABLE_juce_audio_plugin_client && JucePlugin_Build_Unity
bool juce_isRunningInUnity();
#endif
//==============================================================================
namespace WindowsMessageHelpers
{
@@ -168,6 +172,12 @@ bool MessageManager::dispatchNextMessageOnSystemQueue (const bool returnIfNoPend
bool MessageManager::postMessageToSystemQueue (MessageManager::MessageBase* const message)
{
message->incReferenceCount();
#if JUCE_MODULE_AVAILABLE_juce_audio_plugin_client && JucePlugin_Build_Unity
if (juce_isRunningInUnity())
return SendNotifyMessage (juce_messageWindowHandle, WindowsMessageHelpers::customMessageID, 0, (LPARAM) message) != 0;
else
#endif
return PostMessage (juce_messageWindowHandle, WindowsMessageHelpers::customMessageID, 0, (LPARAM) message) != 0;
}


Loading…
Cancel
Save