diff --git a/docs/CMake API.md b/docs/CMake API.md index 942d4b914c..f03752b69e 100644 --- a/docs/CMake API.md +++ b/docs/CMake API.md @@ -599,6 +599,40 @@ attributes directly to these creation functions, rather than adding them later. Unlike the other `COPY_DIR` arguments, this argument does not have a default value so be sure to set it if you have enabled `COPY_PLUGIN_AFTER_BUILD` and the `Unity` format. +`IS_ARA_EFFECT` +- May be either TRUE or FALSE (defaults to FALSE). If TRUE it enables additional codepaths in the + VST3 and AU plugin wrappers allowing compatible hosts to load the plugin with additional ARA + functionality. It will also add the preprocessor definition `JucePlugin_Enable_ARA=1`, which can + be used in preprocessor conditions inside the plugin code. You should not add this definition + using `target_compile_definitions` manually. + +`ARA_FACTORY_ID` +- A globally unique and versioned identifier string. If not provided a sensible default will be + generated using the `BUNDLE_ID` and `VERSION` values. The version must be updated if e.g. the + plugin's (compatible) document archive ID(s) or its analysis or playback transformation + capabilities change. + +`ARA_DOCUMENT_ARCHIVE_ID` +- Identifier string for document archives created by the document controller. This ID must be + globally unique and is shared only amongst document controllers that create the same archives and + produce the same render results based upon the same input data. This means that the ID must be + updated if the archive format changes in any way that is no longer downwards compatible. If not + provided a version independent default will be created that is only appropriate as long as the + format remains unchanged. + +`ARA_ANALYSIS_TYPES` +- Defaults to having no analyzable types. Should be one or more of the following values if the + document controller has the corresponding analysis capability: `kARAContentTypeNotes`, + `kARAContentTypeTempoEntries`, `kARAContentTypeBarSignatures`, `kARAContentTypeStaticTuning `, + `kARAContentTypeKeySignatures`, `kARAContentTypeSheetChords` + +`ARA_TRANSFORMATION_FLAGS` +- Defaults to `kARAPlaybackTransformationNoChanges`. If the document controller has the ability to + provide the corresponding change it should be one or more of: + `kARAPlaybackTransformationTimestretch`, `kARAPlaybackTransformationTimestretchReflectingTempo`, + `kARAPlaybackTransformationContentBasedFadeAtTail`, + `kARAPlaybackTransformationContentBasedFadeAtHead` + #### `juce_add_binary_data` juce_add_binary_data( diff --git a/extras/Build/CMake/JUCEUtils.cmake b/extras/Build/CMake/JUCEUtils.cmake index b883a658c5..94f80e4ded 100644 --- a/extras/Build/CMake/JUCEUtils.cmake +++ b/extras/Build/CMake/JUCEUtils.cmake @@ -1230,7 +1230,13 @@ function(_juce_configure_plugin_targets target) JucePlugin_AAXDisableBypass=$> JucePlugin_AAXDisableMultiMono=$> JucePlugin_VSTNumMidiInputs=$ - JucePlugin_VSTNumMidiOutputs=$) + JucePlugin_VSTNumMidiOutputs=$ + JucePlugin_Enable_ARA=$> + JucePlugin_ARAFactoryID=$ + JucePlugin_ARADocumentArchiveID=$ + JucePlugin_ARACompatibleArchiveIDs=$ + JucePlugin_ARAContentTypes=$ + JucePlugin_ARATransformationFlags=$) set_target_properties(${target} PROPERTIES POSITION_INDEPENDENT_CODE TRUE @@ -1511,6 +1517,84 @@ function(_juce_set_fallback_properties target) get_target_property(plugin_name ${target} JUCE_PLUGIN_NAME) string(MAKE_C_IDENTIFIER "${plugin_name}" plugin_name_sanitised) _juce_set_property_if_not_set(${target} LV2URI "${company_website}/plugins/${plugin_name_sanitised}") + + # ARA configuration + # Analysis types + set(ara_analysis_type_strings + kARAContentTypeNotes + kARAContentTypeTempoEntries + kARAContentTypeBarSignatures + kARAContentTypeStaticTuning + kARAContentTypeKeySignatures + kARAContentTypeSheetChords) + + get_target_property(actual_ara_analysis_types ${target} JUCE_ARA_ANALYSIS_TYPES) + + set(ara_analysis_types_int "") + + foreach(category_string IN LISTS actual_ara_analysis_types) + list(FIND ara_analysis_type_strings ${category_string} ara_index) + + if(ara_index GREATER_EQUAL 0) + set(ara_analysis_types_bit "1 << ${ara_index}") + + if(ara_analysis_types_int STREQUAL "") + set(ara_analysis_types_int 0) + endif() + + math(EXPR ara_analysis_types_int "${ara_analysis_types_int} | (${ara_analysis_types_bit})") + endif() + endforeach() + + if(NOT ara_analysis_types_int STREQUAL "") + set_target_properties(${target} PROPERTIES JUCE_ARA_ANALYSIS_TYPES ${ara_analysis_types_int}) + endif() + + _juce_set_property_if_not_set(${target} ARA_ANALYSIS_TYPES 0) + + # Transformation flags + set(ara_transformation_flags_strings + kARAPlaybackTransformationNoChanges + kARAPlaybackTransformationTimestretch + kARAPlaybackTransformationTimestretchReflectingTempo + kARAPlaybackTransformationContentBasedFadeAtTail + kARAPlaybackTransformationContentBasedFadeAtHead) + + set(default_ara_transformation_flags kARAPlaybackTransformationNoChanges) + + _juce_set_property_if_not_set(${target} ARA_TRANSFORMATION_FLAGS ${default_ara_transformation_flags}) + + get_target_property(actual_ara_transformation_flags ${target} JUCE_ARA_TRANSFORMATION_FLAGS) + + set(ara_transformation_flags_int "") + + foreach(transformation_string IN LISTS actual_ara_transformation_flags) + list(FIND ara_transformation_flags_strings ${transformation_string} ara_transformation_index) + + if(ara_transformation_index GREATER_EQUAL 0) + if(ara_transformation_index EQUAL 0) + set(ara_transformation_bit 0) + else() + set(ara_transformation_bit "1 << (${ara_transformation_index} - 1)") + endif() + + if(ara_transformation_flags_int STREQUAL "") + set(ara_transformation_flags_int 0) + endif() + + math(EXPR ara_transformation_flags_int "${ara_transformation_flags_int} | (${ara_transformation_bit})") + endif() + endforeach() + + if(NOT ara_transformation_flags_int STREQUAL "") + set_target_properties(${target} PROPERTIES JUCE_ARA_TRANSFORMATION_FLAGS ${ara_transformation_flags_int}) + endif() + + _juce_set_property_if_not_set(${target} IS_ARA_EFFECT FALSE) + get_target_property(final_bundle_id ${target} JUCE_BUNDLE_ID) + _juce_set_property_if_not_set(${target} ARA_FACTORY_ID "\"${final_bundle_id}.arafactory.${final_version}\"") + _juce_set_property_if_not_set(${target} ARA_DOCUMENT_ARCHIVE_ID "\"${final_bundle_id}.aradocumentarchive.1\"") + _juce_set_property_if_not_set(${target} ARA_COMPATIBLE_ARCHIVE_IDS "\"\"") endfunction() # ================================================================================================== @@ -1578,6 +1662,9 @@ function(_juce_initialise_target target) PLUGINHOST_AU # Set this true if you want to host AU plugins USE_LEGACY_COMPATIBILITY_PLUGIN_CODE LV2URI + IS_ARA_EFFECT + ARA_FACTORY_ID + ARA_DOCUMENT_ARCHIVE_ID VST_COPY_DIR VST3_COPY_DIR @@ -1599,7 +1686,10 @@ function(_juce_initialise_target target) AAX_CATEGORY IPHONE_SCREEN_ORIENTATIONS # iOS only IPAD_SCREEN_ORIENTATIONS # iOS only - APP_GROUP_IDS) # iOS only + APP_GROUP_IDS # iOS only + ARA_COMPATIBLE_ARCHIVE_IDS + ARA_ANALYSIS_TYPES + ARA_TRANSFORMATION_FLAGS) cmake_parse_arguments(JUCE_ARG "" "${one_value_args}" "${multi_value_args}" ${ARGN}) diff --git a/extras/Build/juce_build_tools/utils/juce_PlistOptions.cpp b/extras/Build/juce_build_tools/utils/juce_PlistOptions.cpp index ac2b70695a..f44db85433 100644 --- a/extras/Build/juce_build_tools/utils/juce_PlistOptions.cpp +++ b/extras/Build/juce_build_tools/utils/juce_PlistOptions.cpp @@ -320,6 +320,13 @@ namespace build_tools addPlistDictionaryKey (*resourceUsageDict, "temporary-exception.files.all.read-write", true); } + if (isPluginARAEffect) + { + dict->createNewChildElement ("key")->addTextElement ("tags"); + auto* tagsArray = dict->createNewChildElement ("array"); + tagsArray->createNewChildElement ("string")->addTextElement ("ARA"); + } + return { plistKey, plistEntry }; } diff --git a/extras/Build/juce_build_tools/utils/juce_PlistOptions.h b/extras/Build/juce_build_tools/utils/juce_PlistOptions.h index fd5d9e973b..54e4b6e72b 100644 --- a/extras/Build/juce_build_tools/utils/juce_PlistOptions.h +++ b/extras/Build/juce_build_tools/utils/juce_PlistOptions.h @@ -86,6 +86,7 @@ namespace build_tools bool isAuSandboxSafe = false; bool isPluginSynth = false; bool suppressResourceUsage = false; + bool isPluginARAEffect = false; private: void write (MemoryOutputStream&) const; diff --git a/extras/Build/juce_build_tools/utils/juce_ProjectType.h b/extras/Build/juce_build_tools/utils/juce_ProjectType.h index 33e39b1b7d..b8c2670d47 100644 --- a/extras/Build/juce_build_tools/utils/juce_ProjectType.h +++ b/extras/Build/juce_build_tools/utils/juce_ProjectType.h @@ -50,6 +50,7 @@ namespace build_tools virtual bool isGUIApplication() const { return false; } virtual bool isCommandLineApp() const { return false; } virtual bool isAudioPlugin() const { return false; } + virtual bool isARAAudioPlugin() const { return false; } //============================================================================== struct Target @@ -111,8 +112,7 @@ namespace build_tools case SharedCodeTarget: return "Shared Code"; case AggregateTarget: return "All"; case LV2TurtleProgram: return "LV2 Manifest Helper"; - case unspecified: - default: break; + case unspecified: break; } return "undefined"; @@ -160,7 +160,7 @@ namespace build_tools case LV2TurtleProgram: return executable; case AggregateTarget: case unspecified: - default: break; + break; } return unknown; @@ -252,7 +252,43 @@ namespace build_tools case Target::StaticLibrary: case Target::DynamicLibrary: case Target::unspecified: - default: + break; + } + + return false; + } + }; + + struct ProjectType_ARAAudioPlugin : public ProjectType + { + ProjectType_ARAAudioPlugin() : ProjectType (getTypeName(), "ARA Audio Plug-in") {} + + static const char* getTypeName() noexcept { return "araaudioplug"; } + bool isAudioPlugin() const override { return true; } + bool isARAAudioPlugin() const override { return true; } + + bool supportsTargetType (Target::Type targetType) const override + { + switch (targetType) + { + case Target::VSTPlugIn: + case Target::VST3PlugIn: + case Target::AAXPlugIn: + case Target::AudioUnitPlugIn: + case Target::AudioUnitv3PlugIn: + case Target::StandalonePlugIn: + case Target::UnityPlugIn: + case Target::SharedCodeTarget: + case Target::AggregateTarget: + return true; + + case Target::GUIApp: + case Target::ConsoleApp: + case Target::StaticLibrary: + case Target::DynamicLibrary: + case Target::unspecified: + case Target::LV2PlugIn: + case Target::LV2TurtleProgram: break; } @@ -268,8 +304,9 @@ namespace build_tools static ProjectType_StaticLibrary staticLib; static ProjectType_DLL dll; static ProjectType_AudioPlugin plugin; + static ProjectType_ARAAudioPlugin araplugin; - return Array(&guiApp, &consoleApp, &staticLib, &dll, &plugin); + return Array(&guiApp, &consoleApp, &staticLib, &dll, &plugin, &araplugin); } } }